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();
}
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.
Rocky
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.
Rocky
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.
That’s a good question – worth considering!!
Rocky
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:
private void
Child_Insert()
{
// insert child data here
FieldManager.UpdateChildren();
}
private void
Child_Update()
{
// update child data here
FieldManager.UpdateChildren();
}
Is there a
reason the DataPortal objects do not call FieldManager.UpdateChildren() in the
Update method?
Copyright (c) Marimer LLC