Root object Save with Children #2514
-
Hi, Background this is for Web and API use only. Up until now I have manually managed children when using CSLA and I thought it was time to utilize CSLA as I keep reading about saving the root is all you have to do. My thoughts were that in the save of the root CSLA does some magic and goes through the collection of children that are Businessbase and utilizes the save on each child. I had a look at the example SimpleNTier and it appears that this is not the case. You need to setup some code in the Fetch and Update to tell CSLA to process the children. I'm OK with that however when I get to the persistence in the database I keep getting an error "System.InvalidOperationException: 'Can not directly save a child object'" I know that you cannot save a child object using .Save() as I have had this before. The root Update is this #region Update
public ArticleEdit Update(ArticleEdit obj)
{
if (obj.IsDeleted)
{
if (!obj.IsNew)
{
// delete data
Delete(obj.ID);
return Create();
}
MarkNew(obj);
}
else
{
if (obj.IsNew)
{
DoInsert(obj);
}
else
{
DoUpdate(obj);
}
// Do any child objects here
var cf = new CategoryFactory();
cf.UpdateItems(obj, obj.ChildObj);
MarkOld(obj);
}
return obj;
} and the UpdateItems code is internal void UpdateItems(ArticleEdit a, CategoryItems lineItems)
{
if (lineItems == null)
{
return;
}
if (lineItems.Count.Equals(0))
{
return;
}
var delList = GetDeletedList<CategoryEdit>(lineItems);
foreach (var item in delList)
{
// code to delete each one.
item.Delete(item.CAID);
}
delList.Clear();
foreach (var item in lineItems)
{
var i = item;
if (i.IsSavable)
{
if (i.IsNew)
{
i = i.Save();
}
else
{
if (i.IsDirty)
{
i = i.Save();
}
}
MarkOld(i);
}
}
} If I change the code to this it works internal void UpdateItems(ArticleEdit a, CategoryItems lineItems)
{
if (lineItems == null)
{
return;
}
if (lineItems.Count.Equals(0))
{
return;
}
var delList = GetDeletedList<CategoryEdit>(lineItems);
foreach (var item in delList)
{
// code to delete each one.
Csla.DataPortal.Delete<CategoryEdit>(item.CAID);
}
delList.Clear();
foreach (var item in lineItems)
{
var i = item;
if (i.IsSavable)
{
if (i.IsNew)
{
Csla.DataPortal.Update<CategoryEdit>(item);
}
else
{
if (i.IsDirty)
{
Csla.DataPortal.Update<CategoryEdit>(item);
}
}
MarkOld(i);
}
}
} However I feel that I am going back to the client side to accomplish this. Is this the correct way to do this or is there a better way? I have also seen code that refers to FieldManager.UpdateChildren(). Should I be using this? Should I have picked a better example to review? Thanks |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 3 replies
-
SimpleNTier uses the factory implementation model for data access. When you use the factory model, you assume a lot of control (and responsibility) for managing the metastate of the business domain objects. Personally, I tend to use the encapsulated invocation model mostly, because it allows CSLA to manage the metastate, and still provides clean separation of concerns between the business layer and data access layer. These models are discussed (along with the other valid models) in the Using CSLA 4 book series, specifically the book on data access. The FieldManager.UpdateChildren supports the encapsulated invocation (and encapsulated implementation) models, and is generally the right answer. If you choose to use a factory model, then the object factory for the root type is responsible for calling factory methods for the child objects. In no case should the child class implement any direct data access method like you've done. Saving child objects is the responsibility of either the root object (inside the data portal operation methods like In the SimpleNTier example you can see how the Update method in OrderFactory saves the root and all child objects. The child objects are saved by delegating to the LineItemFactory, which is responsible for persisting child line items. Contrast that to the ProjectTracker sample, where the ProjectEdit class implements insert and update data portal operation methods that leverage the data portal to manage metastate, and that use the UpdateChildren method to have the data portal invoke the |
Beta Was this translation helpful? Give feedback.
SimpleNTier uses the factory implementation model for data access. When you use the factory model, you assume a lot of control (and responsibility) for managing the metastate of the business domain objects.
Personally, I tend to use the encapsulated invocation model mostly, because it allows CSLA to manage the metastate, and still provides clean separation of concerns between the business layer and data access layer.
These models are discussed (along with the other valid models) in the Using CSLA 4 book series, specifically the book on data access.
The FieldManager.UpdateChildren supports the encapsulated invocation (and encapsulated implementation) models, and is generally the right answer.