I have been struggling with something that I think ought to be so simple that I must just be missing some fundamental piece of the knowledge jigsaw. I am hoping someone here may be able to provide me with a "lightbulb moment".
I have a web application that accesses data from an SQL data source. I have implemented this as a data access layer using the data designer wizard talking directly to the server to create table adapters. I have table adapters for all the individual tables, and also some others that are the result of more complex views or joins. On top of the DAL I have a business layer that is what is actually called from the ASP pages. For standard stuff like gridviews and updating single tables then that is fine and all working.
But the problem I have is that I want to be able to lead my user through creation of new records in the database where they are not using a formview that is a one-to-one mapping with a table. For example, I have a Buildings table where each record includes things like utility references, comments etc, but also has a reference to a separate Addresses table that actually stores the address. There's a FK/PK relationship between Buildings and Addresses.
So what I wnant to do is have a wizard that prompts for the address, then moves on to ask for bits of the other building information, and finally at the end calls code that grabs this data and makes the necessary sequence of BLL calls to set it all up in whatever tables are under the hood. What I don't want to do is create a new address record early on in the wizard in case the operation gets aborted, for example.
Also, because I may have several variations on data gathering, I would like the address input/display form to be a custom control so I can reuse it elsewhere.
Now, if I try and do this with a FormView in one of the wizard steps, then the user gets a FormView generated "Insert" button that (a) gets in the way of my wizard navigation and (b) breaks my requirement of not updating the database until the final wizard step and under code control.
Now it struck me that all I really want is a FormView that gathers DataRow information of a type generated by the data designer as part of the table adapter. I don't actually want a connection to the database at this stage. But I have been unable to make this work.
My rather rubbish solution to this has been to create a contained class within the address control that stores the information in the form controls. I.e - something like this:
public partialclass AddressControl : System.Web.UI.UserControl{public class AddressData {private string _line1;public string Line1NumberBuilding {get {return _line1; }set { _line1 =value; } }private string _line2;public string Line2NumberStreet {get {return _line2; }set { _line2 =value; } }...etcfor all address fields }And then also in the AddressControl:
private AddressData _address =new AddressData();public AddressData Address {get {return _address; }public void UpdateAddressData () { Address.Line1NumberBuilding = Line1NumberBuildingTextBox.Text; Address.Line2NumberStreet = Line2NumberStreetTextBox.Text; ...etcfor all fields... }Finally, in my final wizard button click step I end up doing:
AddressControl2.UpdateAddressData();int addressId = addressbll.AddAddress( AddressControl2.Address.Line1NumberBuilding, AddressControl2.Address.Line2NumberStreet, ...etc// do something with the new address id ...Now this just seems barmy to me for a number of reasons. Firstly I am effectively repeating the information in the AddressDataRow record generated for my in the DAL. Secondly, I lose all databinding with my controls requiring the extremely ugly and unpleasant "UpdateAddressData" method in my customer control.
But the worse thing is that I have to write so much damn boilerplate code. I really want to pass address records around as objects, but I don't want my BLL to either use classes defined at the UI level (AddressData in this case) or to be forced to create such records as part of the BLL when the DataRow already does this.
I did try simply declaring an AddressDataRow object (derived from DataRow by the data designer), but they (a) cannot bind to my form and (b) cannot exist on their own - they always have to be part of a table adaptor.
I have read around a lot on this, but everything I find assumes you want to give complete control on the database create/update access over to FormView and also that one-form-equals-one-table in the database.
I would really appreciate any insight on this. Apologies for the long post but I hope the detail of it will help any answers. I suspect I am tackling the problem from the wrong direction - but I don't know which way to go!
*Bump*
Can anyone shine a light on this for me?
Honestly, the issue here is that you really don't want a form view. A formview represents, well, a form. In your case, you want a wizard that is in control. So your best bet is really just to put your own input fields in the wizard. Keep the results in viewstate or session in an object, and when your wizard is at the finish step, have a property for your control to return the gathered object to pass it to your DAL, or something of the sort.
Yeah its kind of boiler plate code, but 2 way databinding is really when you want a direct bridge to your DAL, and in this case you don't want that. The formview is a databinding controler, not an input control in itself, therefor it simply doesn't do what you want.
CAN it do exactly what you want? Yes. But its honestly lightyears easier to make your own solution for this. Keep using the wizard, but use a custom form. Personaly, the only databound control I use are the combo box/list box and the grid, and rarely, if ever, use 2 way databinding. If I do, then it will be with an ObjectDataSource with custom business code. Its unfortunate, but as soon as you go beyond the prototyping stage, you kindda need boiler plate code.
Thanks very much for the reply. Your middle paragraph has shone some light on things.
It's probably worth me saying that the "wizardness" of my original example is not really the heart of the problem. It's more that there is not a 1-to-1 relationship between the information I need to gather and a table in the database - hence your middle paragraph helping to clarify. I could just as easily lump all my wizard steps into a single from - it's just that this data will end up creating some new records in some tables, and updating some in others.
It looks like this two-way databinding for the database only ever really makes a good demo of MS technology then? Any non-trivial applications have to bypass this and do their own thing? Or, as you say, prototyping.
More or less. The idea behind these things is that a typical WEBSITE (as opposed to a web application), won't do much. Go to some online store's web site, and look. A navigation control...a data repeater for the product listing... maybe a form view for a survey... Obviously the actual checkout has 10 tons of code in it because of all the credit card and security stuff.
Thats what these things are for. And yes, for prototyping. For just about everything else, you'll either have your 100% custom business code and DAL, -or-, you will be using the Object Data Source (which allows you to visualy databind stuff, but you stay in full control, you don't even need a database at all!)
0 comments:
Post a Comment