Initializing Child Collection Objects

Initializing Child Collection Objects

Old forum URL: forums.lhotka.net/forums/t/9226.aspx


MadGerbil posted on Monday, July 19, 2010

Example:

If I have root object (Employee) that has a child collection of objects (Addresses) and the child collection objects (Address) is tied to the root object (Employee) by a guid used as an identification value such that Employee.Id = Address.ParentId.   How do I go about populating the ParentId on the Address object?

For example, if a new Employee object is created it will create a new Addresses collection.  If the user were to use a grid to create a new address for that collection how is the Employee.Id value passed to the new Address object in the Addresses collection?   The Addresses.NewAddresses does take arguments and the AddNewCore() routine (when bound to a datagrid) doesn't take arguments either.

I've been working around this problem by either using Addresses.GetAddresses factory method (even when the Addresses is a new collection on a new Employee object) because that allows parameters.  I set a property on the Addresses collection object so that when AddNewCore() is called that value is available for the creation of a child Address object.   This all seems so bootleg to me - there must be a better way to populate child collection objects with the Id of the parent object so that the objects are all tied together.

tmg4340 replied on Monday, July 19, 2010

A "typical" solution is to utilize the Parent property to walk up the object hierarchy and get the GUID when you need it.  While the Parent property on your Address object is the containing collection, the collection also has a Parent property that would point to your Employee object.  That way you don't have to store the GUID on your Address object at all.

HTH

- Scott

RockfordLhotka replied on Monday, July 19, 2010

Scott is correct, though the Parent properties aren't public prior to CSLA 4, so you need to "re-expose" the property value to gain access in earlier versions.

However, for something like a "foreign key" value as you describe, I don't have my child objects maintain that at all. That's not an object oriented sort of thing - it is a relational sort of thing. So I just pass the parent (and thus its key value(s)) to the child objects when I save them (in the DataPortal_Update() methods).

You can see examples of this in the Expert 2008 Business Objects book and in ProjectTracker (and I'm sure in several other samples - this is always the way I handle this sort of thing).

MadGerbil replied on Wednesday, July 21, 2010

Hmmm... that is interesting - I may have learned a little something there about properly programming objects.   Thank you for the lesson.  I'll apply it immediately.  Smile

DanB replied on Wednesday, July 21, 2010

I've wrestled with this in my mind.  I can't seem to get my head around the value of doubling or tripling (or worse) the object graph being sent across the wire to maintain OO purity.  It seems to me to be kind of a fine line at the end of the day to say relating an object to another via a reference to the other object is  different than relating it via the ID of the other object.  I guess I mean from a pragmatic perspective it just seems like OO purity for OO purity's sake, at the expense of performance.

RockfordLhotka replied on Wednesday, July 21, 2010

If I have an OrderEdit->LineItems->LineItemEdit scenario, there's absolutely zero value in the LineItemEdit objects maintaining an OrderId property. That value will be the same in every child object, and will be serialized back and forth over the network, but it has no value.

Why?

Because the relationship between OrderEdit and its LineItemEdit objects flows naturally from the structure of the object graph. We inherently know that each LIneItemEdit is a child of a specific OrderEdit - that relationship is literally hardcoded into the object model.

So why would I pay the price in terms of serialization overhead, and complexity of maintaining this OrderId property when I don't have to? That seems entirely counter-productive to me.

DanB replied on Wednesday, July 21, 2010

I have code somewhere that is responsible for adding LineItemEdits, and it certainly knows what OrderEdit it is currently dealing with.  Setting the property when the LineItemEdit is created is one line of code.  What other "complexity" do you mean?

We're probably not disagreeing fundamentally, but speaking at a conceptual level...

I don't disagree at all with the accuracy or appropriateness of what you said, but consider that OrderEdits are likely associated with a Customer, and let's say like all objects in the application that is associated with a Division, which in turn associated with a Company because the app is multi-company... would you normally start every object graph in the application with a CompanyEdit?  At some point don't you break the chain and establish some parent context in code by setting a property instead of having Parent properties go all the way to a CompanyEdit every time?

So, aren't we free, and even required, to decide the root of the object graph to best supports a particular use case (including performance, not just OO purity)?  Aren't I always deciding whether a collection is edited through its editable parent... OR ... that the best option overall is a dynamic list used by some managing code that has to set the parent ID when adding new items?

Marjon1 replied on Wednesday, July 21, 2010

In a normal Parent-Child-Grandchild scenario, the entire object graph containing all 3 objects is sent at the time of calling the relevant DataPortal_XYZ method as part of the save. Therefore when the child or grandchild are passed the any of the 3 objects,  there is no additional serialization / network traffic.

The concept of storing an ID, really only works well for the likes of GUID's otherwise there is a bit more complexity of getting that information into the children objects after the parent has saved and then using it as part of their inserts / updates instead of just always using the Parent.ID value.

Seems more likely to introduce some weird bugs (i.e. an Id isn't correctly set on a child object or is moved to another list without changing the ID value).

Relating the objects by reference enforces the relationship, if the child is removed from the parent then there is no more relationship; if you add an ID into the mix, then you must also remember to remove this part of the relationship and it becomes your way of identifying the relationship. The fact that it is attached to a parent becomes secondary, which I think is what you want to avoid.

 

DanB replied on Wednesday, July 21, 2010

Well, I thought about this more after my last post, and Marjon's response confirms to me that we're saying two different things.  In cases where we're creating the entire object graph I don't disagree with any of what's been said.

Let me try my point a different way...

Simply put, in cases where we DON'T need to send the entire object tree to the server anyway, should we favor or strive for designs where we can minimize the traffic?

So, think of a case where you have a Customer which has a child collection of Contacts, each with a child collection of PhoneNumbers.  The Customer also has a collection of Addresses.  Do we really want to send a graph of 20 objects to the server to change one phone number?

(And yes, by the way, I prefer GUID IDs.  I admit and agree my response was tainted by my routine use of them.)

 

RockfordLhotka replied on Wednesday, July 21, 2010

In this case, you might want to look at the diffgram sample app. It allows for voluntary enlistment by objects in terms of being transferred (in whole or part) to the server, while maintaining (to some degree) the logical structure of the object graph.

When using the diffgram approach, the parent would enlist and provide its key, so the server code (in the DAL) would have access to that key without the need to duplicate that value into every child over the wire.

Copyright (c) Marimer LLC