From Rockford Lhotka's Expert C# 2008 and VB 2008 Business Objects books
I just posted a new preview version of 3.5 for download. The VB code includes a new concept around simplifying how child objects are persisted - create/fetch/insert/update/delete. The goal is to save code in root objects and list objects, and to standardize the coding model for all objects.
The code in the download is not completely tested, but basic tests all pass and so I think it is worth putting out for people to kick the tires. Regardless of whether you use C# or VB, if you get a chance to build some business classes against the VB framework your feedback would be invaluable!
I want to be very clear that this is all entirely optional. If you don't like it (because it does use reflection just like the data portal always has) then you can continue to use the model from 3.0 and earlier. Nothing compels you to use this new model (except for radical simplification of code ), and if you don't use it then you incur no extra overhead or cost.
The new child object pattern is this:
[Serializable]public class Child : BusinessBase<Child>{ internal static Child NewChild() { return DataPortal.CreateChild<Child>(); }
internal static Child GetChild() { return DataPortal.FetchChild<Child>(); } private Child() { MarkAsChild(); } private void Child_Create() { // initialize new child here }
private void Child_Fetch() { // load child data here }
private void Child_Insert() { // insert child data here }
private void Child_Update() { // update child data here }
private void Child_DeleteSelf() { // delete child data here }}
Please note that no calls to MarkNew() or MarkOld() are required, they are all handled by the data portal just like they are for root objects.
The new editable root (parent) pattern is this:
[Serializable]public class RootParent : BusinessBase<RootParent>{ // other class code here ...
protected override void DataPortal_Insert() { using (SqlConnection cn = new SqlConnection(...)) { // insert parent data here
FieldManager.UpdateChildren(); } }
protected override void DataPortal_Update() { using (SqlConnection cn = new SqlConnection(...)) { // update parent data here
FieldManager.UpdateChildren(); } }}
The call to UpdateChildren() automatically cascades appropriate insert/update/delete calls to all child objects (including collections).
The new editable root list pattern is this:
[Serializable]public class ChildList : BusinessListBase<ChildList, Child>{ // other class code here ...
protected override void DataPortal_Update() { using (SqlConnection cn = new SqlConnection(...)) { Child_Update(); } }}
The only reason you still need to override DP_Update() is so you can manage the connection details (or LINQ context, or whatever).
The new editable child list pattern is this:
[Serializable]public class ChildList : BusinessListBase<ChildList, Child>{ internal ChildList() { MarkAsChild(); }
// other class code here ...}
Notice that there is no data access code here, because child updates are now handled entirely by the base class.
Rocky,
I noticed in ProjectResources you are passing in an array of Assignment to populate the ProjectResource list. The GetProjectResources method is executed in the DataPortal_FetchChild method of Project. The ProjectResources static factory Get method then calls return DataPortal.FetchChild... which in turn calls Child_Fetch... GetProjectResource which is called in ProjectResources.DataProtal_ChildFetch also uses the same DataPortal.FetchChild pattern.
The question is, why do we keep going back to the DataPortal when we are already in the data portal context? How come you don't call use the "deep data" pattern where the child collection and child are populated by passing the data (reader) into the constructor?
One major enhancement in CSLA 3.5 is that the data portal now supports the concept of child objects.
Notice that the call is to FetchChild(), not Fetch(). The data portal includes special treatment of child objects – very lightweight, but with the same coding structure as a root object.
One of the biggest training issues with CSLA has always been that root objects and child objects are coded differently. The very structure of the code (which methods you write and how they are called) are different.
The new child support in the data portal means that the coding structure for a root and child are the same. The method names are slightly different – Child_XYZ instead of DataPortal_XYZ – but that’s good (imo) because it clarifies whether the object is a root or child. But the structure is the same, so every object has the same “look and feel”.
If you don’t like the new model, and prefer the old 1.0-3.0 coding style, you are free to use that approach. Nothing in 3.5 blocks you from using the older coding technique.
But I like the new approach because the code is much more consistent across all the objects – making training easier, and even simplifying code-gen or the use of snippets.
Rocky
I agree with Rocky. It is one of the issues when I was trying to code the Code Complete templates. I am sure it will simplify my job dramatically and it comes on time as I am in the process of re-writing the templates for version 3.5 and LINQ.
Thanks
Philip
Hi Rocky!
Is there really a need for calling MarkAsChild() in the constructor of the child? I don't call MarkAsChild(), it is called automatically by DataPortal.CreateChild<Child> and DataPortal.FetchChild<Child> like MarkOld() and MarkNew().
Yavuz
private void Child_Insert() { // insert child data here FieldManager.UpdateChildren();
}
private void Child_Update() { // update child data here FieldManager.UpdateChildren();
That’s a good question – worth considering!!
From: rsargent [mailto:cslanet@lhotka.net] Sent: Friday, August 22, 2008 7:09 AM To: rocky@lhotka.net Subject: Re: [CSLA .NET] CSLA .NET 3.5 enhancement - child persistance
If my child object contains children do I need to change the Child_Insert and Child_Update methods to look like the following:
Is there a reason the DataPortal objects do not call FieldManager.UpdateChildren() in the Update method?
If you have more than one child, or just want to simplify your code, you can just call
FieldManager.UpdateChildren()
And let the field manager do the work for you.
From: ajj3085 [mailto:cslanet@lhotka.net] Sent: Friday, August 22, 2008 8:12 AM To: rocky@lhotka.net Subject: Re: [CSLA .NET] CSLA .NET 3.5 enhancement - child persistance
I haven't had a lot of experience with Managed properties yet, but I haven't found a need to use FieldManager at all. All I do in my Child_Update / Insert is the data access code.. if the child has children, then I call DataPortal.UpdateChild. For example: DataPortal.UpdateChild( ReadProperty( SerialNumbersProperty ), item ); Where SerialNumbersProperty is a BusinessListBase subclass property.
The book is on a “revised” schedule, which is to say we’re shooting for a December release – which is putting a strain on everyone (me, publisher, reviewers) but we’re working toward that end.
From: ajj3085 [mailto:cslanet@lhotka.net] Sent: Friday, August 22, 2008 11:46 AM To: rocky@lhotka.net Subject: Re: [CSLA .NET] RE: CSLA .NET 3.5 enhancement - child persistance
Thanks for the tip... is the book still on schedule? "> Amazon lists 9/5/2008 as the ship date.