Objects Containing Objects and the ObjectDataSource

by Ira 23. March 2008 19:08

Ok, I ran into a major problem not so long ago. This problem stemmed from a DataObject that had a child object within it, here in referred to as a "complex object". When I put an ObjectDataSource on my page and bound to my business layer with my complex DataObject, for some reason only the simple properties would show up. Simple properties being those that are passed by value and of a .NET system type. My custom typed property never shows up in my data bound control. Hmmmmm...

 

After some research on complex objects and the ObjectDataSource, I found some examples of people adding the extra fields and type casting the Container.DataItem to expose the inner properties of the child object. This in turn would get them the data they needed. Then using the ObjectDataSource's OnUpdating or OnInserting event, they would then re-type cast the object while grabbing the values from the page and stick it into the dictionary of values in the event arguments. Whew! That is hard to explain, and in my opinion even uglier to look at! The biggest problem with that solution is that you will need to add in those event handlers on every web page that uses these complex objects. There has to be a better way.

 

There is, and it involves making some adjustments in the business layer and creating some shells for your complex objects. First let's build a data model. We will make a Person object that will contain a State object like so:

Now we need to make a presentation shell that gives us access to all the properties of Person, as well as giving us access to the properties of the State object within the Person object.

Here are the properties of our PersonPresentationShell object:

 

As you can see the PersonPresentationShell has a public field of Person. All the properties of it are just accessors of the Person object and the State object it contains. This makes for all of our properties being of .NET system types. Now let's have a look at the constructors:

As you can see, the first constructor just initializes the Person and State objects. This will be used by the ObjectDataSource to re-build our data. The second constructor will be the one we use when coating all our Person objects for presentation. Now we will have a look at our business logic:

You can see in the GetPeople method of the business layer, we get a list of Person from our data layer and convert them into a list of PersonPresentationShell and return them for display. Our Insert, Update and Delete methods all accept a PersonPresentationShell as an argument then pass the Person object it contains down into the data layer. Using this approach, put an ObjectDataSource on the page, configure it, and bind a GridView and a DetailsView to the data source and run the application.

Now all of the data controls work exactly as expected. It seems like a long way to go, but I feel like it is a pretty elegant solution. This ensures that my data and business layers have DataObjects for communication and my business layer and UI have PresentationShells for communication. All of the wrapping an unwrapping happens in one place, the business layer. Maybe in a future .NET release the ObjectDataSource will support "complex" objects.  

If anyone has a better solution to this, please feel free to share!

Download the code:
ComplexDataObjects.zip (11.34 kb)

 

kick it on DotNetKicks.com

Tags: , ,

ASP.NET | C#

Comments

4/2/2008 5:08:57 AM #

Ralf Koch

I actually came to the same conclusion after thinking and doing some research.
Maybe they get some more features on the ODS in the future but so far I like it a lot.
It could be a pattern as well, if not somebody else has the solution to complex objects...

"Object Flattener Pattern"


God bless

Ralf

Ralf Koch United States

4/3/2008 12:07:24 AM #

Ira

You're right. I'm just hoping for a better ODS in the future, or possibly extending the ODS class to fit my needs. I needed a solution quick this time though and this pattern got the job done.

Ira United States

4/4/2008 10:14:41 AM #

Vladimir Kelman

Good solution!
Isn't it a little bit more secure to have Person as a private member of PersonPresentationShell object and add public "get" property?

Vladimir Kelman United States

4/7/2008 11:19:10 AM #

Ira

Yes, a private variable with only a get accessor would do the trick. However, In my code I declare the Person object internal. That way there is no access to it outside of my business assembly.

Ira United States

5/19/2008 2:02:07 PM #

Vladimir Kelman

We're now using your "shell" approach - thanks again for a good idea.
There is one problem we're trying to find most convenient solution:
Suppose you have tPartner table and each (business) Partner might have several point of contacts which are stored in tPOC table. To define that one-to-many relationship tPOC table has PartnerID FK field.
Partner object may or may not include a collection of POC objects. It's not absolutely necessary, but might be convenient allowing to modify that collection in memory (add/delete Partner's POCs) and then to save both Partner and its POCs in one transaction.
On the other side, it is convenient to include some (probably partially populated) version of Partner object as a property of POC object. For example, we could use overloaded Partner.Partner(int partnerID, string parnerName) constructor. Then we naturally would use your UI Shell approach to display a list of POCs along with their PartnerNames in a grid/list view.
A problem is: a bit later someone decides that this list should also include PartnerURL. We'll need to modify DAL, add a new overloaded Partner constructor, add new properties to POC's UI Shell object... to much work. Question is: how to make it easier to customize, more automatic?

Vladimir Kelman United States

5/19/2008 6:01:20 PM #

Ira

Unfortunately I have run into the same problem. When modifying a parent or child object that you also want displayed in the shell object, It is obviously going to have to be added to the DAL to populate your new property in the object. That being said, it also has to manually be added to the shell object. Now one thing you might try is creating your own rendition of the ObjectDataSource. It can be done and you can have it recurse through a set number of levels in the object tree. I just haven't had the time to give that solution a shot. If that was the case, you could then simply use the Bind statement of the ASP.NET data control to bind deeper in your tree.

Hope this helps.

Ira United States

5/19/2008 6:07:29 PM #

Vladimir Kelman

Thank's. I'll try to do something after I get more familiar with ObjectDataSource (I'm trying tolearn too many things at the same time).

Vladimir Kelman United States

3/20/2009 5:04:40 PM #

Paul Whitaker

I'm trying to use this from within a repeater, and my object is always empty when I call the update method on the ObjectDataSource. But this helped me feel like I'm getting closer. Thanks. Smile

Paul Whitaker United States

Comments are closed

Powered by BlogEngine.NET 1.5.0.7
Theme by Mads Kristensen

About Me

IraIra
I'm just another developer from Florida.

 

Sponsors

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

All code samples on this website are free for download, use, and modification with no warranty nor any implied warranty. Liscensed by:

Creative Commons License
This work is licensed under a Creative Commons Attribution 3.0 United States License.