Recursive save

Posts   
 
    
kievBug
User
Posts: 105
Joined: 09-Jan-2009
# Posted on: 18-May-2011 19:40:57   

Hi,

I have a typical master-detail case. Here is the structure:

Entity: Master Fields: Id (PK), Caption, CurrentDetailId (FK,Nullable) Navigators: CurrentDetail based on M : (0-1) the relation for CurrentDetailId -> Detail.Id Details based on the 1:m relation for Id -> Detail.MasterId

Entity: Detail Fields: Id (PK), Caption, MasterId (FK,Not Null) Navigators: None

I want to save master with details and set Master.CurrentDetail to one of the new details that are going to be created:


var master = new MasterEntity {Caption= "m1"};
master.Details.Add(new DetailEntity { Caption = "d1" });
master.Details.Add(new DetailEntity { Caption = "d2" });
master.Details.Add(new DetailEntity { Caption = "d3" });
master.CurrentDetail = master.Details.Last();
adapter.SaveEntity(master);

When I save it, it throws exception. I understand that it is a cyclic reference to the detail that is not created yet when we save the master, but anyway it is still possible to save such structure into the database.

As for me it makes sense to support this case, you have all dependencies in place. And you are building the correct order of saving the graph, but you are not covering this (I'd say typical) scenario.

  • Is there any problems with it?
  • Is it going to be supported at all?

It is a nightmare to handle such cases(do not forget about it), but also even bigger problem if I use a UnitOfWork - I can not add it twice, so I need to use update entities derectly or smth like this.

  • Any suggestions, commets?

Thanks, Anton

Walaa avatar
Walaa
Support Team
Posts: 14946
Joined: 21-Aug-2005
# Posted on: 18-May-2011 20:38:39   

adapter.SaveEntity(master);

I don't see recurse being passed to the Save method. Anyway tt needs an update after the insert of the master entity.

var master = new MasterEntity {Caption= "m1"};
master.Details.Add(new DetailEntity { Caption = "d1" });
master.Details.Add(new DetailEntity { Caption = "d2" });
master.Details.Add(new DetailEntity { Caption = "d3" });
adapter.SaveEntity(master, true, true);

master.CurrentDetail = master.Details.Last();
adapter.SaveEntity(master, true, true);
kievBug
User
Posts: 105
Joined: 09-Jan-2009
# Posted on: 18-May-2011 21:57:23   

Recurse is true by default.

Yeah that is what I need to do manually, and do not forget about it, but as for me the framework can take care of it, right?

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 19-May-2011 07:09:02   

Hi Anton,

This is unavoidable, because:

  1. A depends on B, and B depends on A. For simple graphs is easy to see that you need a save and an update, but for large and complex graphs this is just cumbersome.

  2. The save action of A is in progress at the time B is waiting for B to be saved. This is doe like this to avoid loops. The same problem arises if you only want to insert Master and its LastDetail (which is also new).

What should the framework do? IMHO, this is a programmer concern. The code Walaa suggested is the way to go in this case. You can add all action into a UnitOfWork or into a Transaction to make the an atomic commit later.

David Elizondo | LLBLGen Support Team
kievBug
User
Posts: 105
Joined: 09-Jan-2009
# Posted on: 19-May-2011 15:04:49   

Well, I wouldn't say that it is unavoidable :-) and I do not see any problems with implementing it, you just need to distingush that case/type of relation when building a dependency graph.

IMHO it would be better if framework does it automatically rather than developer care about it, you have all information about the relations and etc, needed to save the entity.

So as I understand no plans to support it at all (am I right ?) :-( that's bad as for me.

Thanks, Anton

kievBug
User
Posts: 105
Joined: 09-Jan-2009
# Posted on: 19-May-2011 15:21:36   

The code provided works fine.

But what if the entity comes from the Presentation Layer ? Then I need to check for this case and correctly handle it everytime I save such entity.

How can I do this with UnitOfWork? I cannot just add it twice to the UOW, it won't work. The only possible case with UOW at least that is going to work in the example provided when entities are new - is add entity to save with current detail set to null, and add update entities directly code to update this field. Is there a better option?

See, it is much harder to do this manually, especially in generic case when you have something that can save different/any entity, rather than have a framework to support it.

Anton

MTrinder
User
Posts: 1461
Joined: 08-Oct-2008
# Posted on: 19-May-2011 22:25:13   

You could do it within a transaction if you want to make the whole save atomic - the unit of work is really designed for collecting a set of changes together from a user interface.

I'm fairly sure there are no plans at the moment to support this within the framework, but I can check with the development team if you'd like?

Matt