Graphs inserting unwanted rows in Db

Posts   
 
    
csmac3144
User
Posts: 74
Joined: 12-Sep-2007
# Posted on: 15-Mar-2009 19:53:08   

I am fairly competent with LLBLgen Pro now, however I don't seem to understand some of the basics. I repeatedly run into problems where graphs (objects fetched using prefetch paths with several associated collections) are inserting additional rows into the child collections when I try to persist. It is a large app and hard to isolate sample code to demonstrate. I just thought there might be some general guidelines around this issue, or maybe some threads where this topic has been discussed already...?

I just did a little more testing.

I had an object called Product.

Product has a 1-many with Formulation.

When I created a NEW Product I could do this (pseudo-code) (new Product entity):

formulation = GetOneFromDb(fid);
product = new ProductEntity();
product.Formulation = formulation;
adapter.SaveEntity(product);

This works fine so far.

However when I do the following (use an existing product fetched from db):

formulation = GetOneFromDb(fid);
product = GetOneFromDb(pid);
product.Formulation = formulation;
adapter.SaveEntity(product);

I end up with a duplicate of the formulation record in the Formulation table.

Finally if I do this (use the int PK value directly):

formulation = GetOneFromDb(fid);
product = GetOneFromDb(pid);
product.Formulation = null;
product.FormulationId = formulation.Id;
adapter.SaveEntity(product);

Everything works fine now.

Can someone PLEASE explain the rules about when to assign objects to properties such as:

product.Formulation = formulation;

versus setting the Id directly:

product.FormulationId = formulation.Id;

This is very confusing to me. I apologize if I missed a thread or missed it in help file...

Steve

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 15-Mar-2009 21:35:38   

Hi Steve,

Recursive saves are performed by default. This means that the DataAccessAdapter SaveEntity() logic will check whether included entities also have to be saved. For example, if the formulation.IsNew is true and it has some dirty fields, the adapter.SaveEntity will try to save it as well (perform an insert). What you can do is use the SaveEntity overloads that accept the recurse parameter and pass _false _to it.

When you assign the Id it works nice because you are not doing PK-FK sync, you are just setting a field value.

(Edit) For more info please read Recursive saves and PK-FK synchronization

David Elizondo | LLBLGen Support Team
csmac3144
User
Posts: 74
Joined: 12-Sep-2007
# Posted on: 15-Mar-2009 21:41:34   

daelmo:

Thanks for the response. The strange thing is that I checked IsNew and IsDirty on the Formulation object just before the save, and both were false. I will continue to investigate this, but I am still not clear on what best practices are around using Id versus object assignment. Well, I am fairly clear that when dealing with new entities you have to assign the object since there is no id yet (using autoincrement in SQL Server). Otherwise I am still unsure...

csmac3144
User
Posts: 74
Joined: 12-Sep-2007
# Posted on: 16-Mar-2009 00:31:01   

Well after more research I think I have found a source for the weird behavior. A while back I got some code from this forum called CloneHelper() which clones entities. We used this to attempt to implement a sort of versioning system, so each change to an entity resulted in a new db row, with the old row getting IsActive=false.

This clone code was causing strange results -- maybe not that code itself but the way we were using it.

It would be nice to have some support in LLBLgen for handling cloning of this type -- or is that too difficult to implement?

Walaa avatar
Walaa
Support Team
Posts: 14993
Joined: 21-Aug-2005
# Posted on: 16-Mar-2009 08:47:35   

There are many samples on the forum on how to perform cloning and deep cloning.

csmac3144
User
Posts: 74
Joined: 12-Sep-2007
# Posted on: 16-Mar-2009 12:28:15   

Walaa wrote:

There are many samples on the forum on how to perform cloning and deep cloning.

Thanks Walaa. I actually used one of those samples (CloneHelper()) in our project. For whatever reason that was causing a lot of very subtle bugs related to recursive saves.