Problems with ObjectDataSource
ASP.NET 2.0 comes bundled with a control called ObjectDataSource. At first it looks like it is a perfect solution for all OOP lovers like me. The problem is that in practice it is completly unusable.
There are several problems with the control, the greatest of which are the fact that all objects that are to be updated by the control are required to have a default, parameterless constructor since the Update method takes as a sole parameter the object of a specified type created by none other than the ObjectDataSource control.
(another method is to provide an update method that takes simple parameters representing updated object's properties such as name, age etc. but this solution is even worse since it requires separate methods for every combination of parameters, and defeats OOP feature - the inheritance - altogether).
Now where exactly is the problem? You may think hell I can go with having a default constructor on every object since I will probably need it anyway to support the [Serializable] attribute. But wait! There is one more problem with the control. It creates our business object and sets its the properties!!! Now what is wrong with that you ask? Once the business object is created ALL its fields are set to initial values such as null/1/1.0/false. Next, each property that was bound using the two way databinding mechanism (Bind) is set to a new value taken from the html form. This is of course ok. But what happens to the properties that were not bound using Bind? AHA! Now's the catch. They are not updated with any value and so we end up having a business object with only some of its properties set.
A more realistic example: given a business object User with properties such as Id, FirstName, LastName, Age, Login, Password and a form on which we use an ObjectDataSource control and a FormView control to edit just the Login and Password. Of course the FormView allows us to specify the DataKeyNames so the Id property will be preserved - we will need it to update the right record in the database. The form is first displayed and both textboxes are populated with user's Login and Password. User edits the data and decides to save them. On PostBack the magic happens and the ObjectDataSource creates a brand new User object, sets it Login and Password property with the new values from the form. Such an object is then passed to an Update method expecting a User object. But what to do with such an object? We cannot save it to the database since there is no way to determine if a given property's value is the default value or a value just set by someone and we cannot just save all the new values because that would mean loosing the data that was not edited.
In most cases we cannot even compare the property value with the default value for that property or the value from the database since given an Age=0 we cannot tell if it results from a user's setting or the fact that it was not set at all.
Now. There are multiple workarounds for this problem. One mentioned earlier is to use a separate Update method for each combination of parameters.
The other is a hack. It is possible to fool the ObjectDataSource so that it thinks it uses the parametrized Update method. It is necessary in order to get the Keys and Values from the form. If the Update method is used, there is no way of accessing those values. Next step is to intercept the Updating event. There you will have access to a collection of Keys and Values read from the form (accessible through the event args). You can than get the destination object from the database or from some other location, and copy the new values to its properties using Reflection. Once you have copied the new values to the business object you have a stiutation where the object is properly set: properties present on a form are updated, the other ones are set to the original values and not the default ones. There is just one problem. What to do with such an object and what about the parametrized method? We still need them yes? No! After copying the new values to a business object we have to clear the ObjectDataSourceMethodEventArgs's InputParameters collection and add to it just one parameter - our business object. The good news is that it is only after the Updating event when the propert Update method is selected to be called. The method is selected based on the InputParameters and since there is only one, the Update method expecting our business object will be used :-).
Example code:
void DataSourceControl_Updating(object sender, ObjectDataSourceMethodEventArgs e)
{
IOrderedDictionary inputParameters = e.InputParameters;
// Get the business object
object element = GetElement();
// Copy the values from the form to an object - the hard part
CopyValues(element, inputParameters);
// Clear the parameters list and add a single object to it
e.InputParameters.Clear();
e.InputParameters.Add("element", element);
}
To fool the ObjectDataSource control we have to delete DataObjectTypeName attribute but do it from the html view and forget about using the designer for edditing the control from there after.
Of course the above mentioned methods are not something I would recommend, but for a starter this is the only way I'm aware of you can use the ObjectDataSource. The other way is to write your own ObjectDataSource. This is exactly what I have done and will provide a complete solution in a few days.
1 Comments:
Agreed. Seems like a reasonable solution to a real problem. I'm just getting into the 2.0 framework and as nice as it all sounds there's still a fair amount of gotchas when it comes to implementation...
By Anonymous, at 6:15 PM
Post a Comment
<< Home