I have an object with a child list. I call Save() on the root level object and use the FieldManager to call update on the child objects. It all seems to be working but in the end, the changes are not persisted.
I have stepped through the code to ensure that my child objects have the most recent values and they do.... I use Transactional attribute with TransactionScope as they type. Do I have to call Commit or is this done by the CSLA framework?
Any clues?
Mike B
Here is the Child_Update code:
[RunLocal()]
[Transactional(TransactionalTypes.TransactionScope)]
private void Child_Update(object parent)
{
using(ObjectContextManager<InformEntities> manager
= ObjectContextManager<InformEntities>.GetManager("InformEntities", true))
{
InformModel.TimesheetActivity activity = new InformModel.TimesheetActivity();
ObjectToEntity(activity);
activity.EntityKey = new System.Data.EntityKey("InformEntities.TimesheetActivities", "Id", activity.Id)
manager.Context.Attach(activity);
manager.SaveChanges();
}
}
You should read Chapter 18 (and 17) of Expert 2008 Business Objects to get an understanding of the data access models supported by CSLA .NET.
At a high level:
Thanks for the reply Rocky:
So, would 1 and / or 2 stopped my object from saving. You stating that the RunLocal and Tansactional attributes are ignored at the child level tells me no. This leaves the DataPortal_XYZ method. I do call UpdateChildren(this) from the parent method, and my Child_Update(...) does get called....I get no exceptions, no errors, but also, no persistence.
I have read chapter 18 of your book and I understand the data access methods which should be used. Well I thought I did anyway. The RunLocal and Transactional attributes were remnants left behind before I implemented Child_Update (Originally I had everything as a root level object). The classes were all genereated from a template using MyGeneration...
Any idea why this will not save? Here is my parent DataPortal_Update(...) function. I am using Entity Framework for data access.... Anything apparently wrong with this? Remember, the Child_Update() is getting called.....
[RunLocal()]
[Transactional(TransactionalTypes.TransactionScope)]
protected override void DataPortal_Update()
{
using (ObjectContextManager<InformEntities> manager
= ObjectContextManager<InformEntities>.GetManager("InformEntities", true))
{
InformModel.Department newObj = new InformModel.Department();
ObjectToEntity(newObj);
newObj.EntityKey = new System.Data.EntityKey("InformEntities.Departments", "DepartmentId", newObj.DepartmentId);
manager.ObjectContext.Attach(newObj);
manager.ObjectContext.SaveChanges();
FieldManager.UpdateChildren(this);
}
}
Yeah, I think your right. Unfortunately, I became really overwhelmed with my generated classes trying to change root objects to child objects etc... so I deleted them all and started handcoding them from scratch to get a better feel for the framework and how it works....
My only problem now is I cannot figure out the indtended way to create child objects..... Even with the book, I find it difficult to follow ProjectTracker project.
If I have a Order object with an OrderItem collection. Am I supposed to create a AddNewOrderItem(....) method in the Order object where I pass all the arguments? Or do I just ask the Order for a new Blank Order Item, fill out the details and pass back to the Order for saving?
Thanks for the reply....
Mike B
I tend to create my classes following a consistent structure,
and this was a reason I created the child data portal concept – to increase
the consistency.
So I tend to create a factory on every class (public for a root,
internal for a child) and have that factory call the data portal.
Then I implement the real work in the DataPortal_XYZ or Child_XYZ
method (or in a factory object).
Typically a child object is contained in a collection, and
collections have Add() and AddNew() methods. When possible, I’ll support
AddNew() by overriding AddNewCore():
protected override object AddNewCore()
{
var item = ChildType.NewChild();
Add(item);
return item;
}
If that’s not realistic because some values are necessary
to create a new child, then I won’t take that approach, and instead will do
one of two things
1.
Have a public static factory method on the child class so anyone
can create a child (and then use Add() to add it to the collection)
2.
Have an overload for Add() on the collection that takes the
required parameters, calls the internal factory method on the child class to
create the child, and then calls Add() to add the item to the collection
At this point though, we’ve hit a point where style and
choice enters the picture. It doesn’t really matter to CSLA how you
choose to do this (there are variants beyond these two) as long as you
ultimately have a child object and Add() it to the collection.
Rocky
Thanks for the reply Rocky.... Makes perfect sence, I figured it was really up to the "implementer" but I thought maybe there were prefered methods.
Mike B
Copyright (c) Marimer LLC