Saving circular references? why not?

Posts   
 
    
kievBug
User
Posts: 105
Joined: 09-Jan-2009
# Posted on: 14-May-2013 20:10:21   

Hey guys,

I have a question regarding the sequence of saving data. When we call adapter.Save(Entity, true, true) llblgen internally determines the sequence of the actions(inserts, updates). So my question is regarding the case when I have a schema like this:

Entity: Main ID int not null, Name nvarchar(50), DefaultDetailID int <- nullable

Entity: Detail ID int not null, Name nvarchar(50), MasterID int not null

As you can see it is "improved" version of Master - Detail 1:M relation, when master record has a reference to the detail too.

After doing all the code generation we can write the sample code:


                    var detaultDetail = new DetailEntity
                    {
                        Id = 1,
                        Caption = "Detail 1"
                    };

                    var main = new MainEntity
                    {
                        Id = 1,
                        Caption = "Rec 1",
                        DetaultDetail = detaultDetail,
                    };

                    main.Details.Add(detaultDetail);

                    adapter.SaveEntity(main, true, true);

There is no problem to re-write the code with two calls(insert + update), so that the data is saved, but I'm just wondering is there any reason why it can not/wasn't added to llblgen?

You have everything in-place when determining the sequence and queries to be executed so why not to handle it automatically ?

Thanks, Anton

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 15-May-2013 08:17:32   

Hi Anton,

IMHO, LLBLGen can't take the responsibility of deciding on this ambiguous situation, where A depends on B and viceversa. If Main.DefaultDetailID is always needed for that table, the nullable flag is just there to make the schema work, but it doesn't reflect the reality. This could be a sign for normalize the Main table, but that's just my opinion.

Now, in your example it looks like a simple scenario, but it could become very complicated in a more deep graph with similar circular references, where LLBLGen has to check all the FK fields and find candidates for deferred updates. It would be also not transparent because you are sending saves on new entities (inserts), not updates. So people with DB triggers, or concurrency controls might be affected. IMHO, you must do it in two phases: insert, then update, or create a natural 1:1 table (MainDefaultDetail) that keep that info separately.

David Elizondo | LLBLGen Support Team
kievBug
User
Posts: 105
Joined: 09-Jan-2009
# Posted on: 15-May-2013 15:17:23   

Hmm as for me the schema seems to be normilized, why do I need another table for it?!

In such schema, people with triggers won't be affected, because you just can save the schema with just inserts, and for sure everybody understands it.

From another point of view, Llblgen has functionality to do a recursive saves which basically will save the graph of entities - it determines the query sequence for the graph, and executes them, and I do not need to do Saves for each entity. In this case, the sequence can still be determined and the graph can be saved. It would be much better if I'm as a developer do not need to care about it and write a bit "dirty" code while it could be handled by the framework.

I do understand that this feature need some/lots of work, re-factoring, etc. As for me it worth it, not sure about the others.

Thanks, Anton

Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 15-May-2013 19:28:03   

In that Case it's not defined which is the master and which is the detail, as both have FK to the other.

So the framework can't determine how to traverse this graph. i.e. which Entity should be inserted first. Which is a good question in case PK are generated at the database side (sequences). And you can imagine how that logic can be devastating in much bigger and complex graphs.

kievBug
User
Posts: 105
Joined: 09-Jan-2009
# Posted on: 15-May-2013 19:33:42   

One dependency is optional, because the column is nullable. Thus Update can be generated for it and executed after insert query. This information is already there available, and it can be used while building a graph. You can just skip such relation while adding it to the graph, and after that just update, ideally it should be done only if there is a cycle.

It is possible, we are actually doing similar stuff and everything seems to be working correctly.

But still it will be good if it can be added to the framework, so that people don't do it manually.

Anton

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 16-May-2013 15:31:19   

Reply to a similar question: http://www.llblgen.com/tinyforum/GotoMessage.aspx?MessageID=67575&ThreadID=12160

The update can be postponed indeed, but we didn't implement it as it's mainly a sign the model should be reworked. In your particular case the FK field is already nullable so the requirement of a nullable FK field isn't a problem, but it might be.

Additionally, the cycle itself causes a problem with finding the right order in which the entities have to be saved. One could argue that the side with a nullable FK field is the one which should come first, but what if both are nullable? Picking the wrong one might cause a problem later on in the graph as the topological sort algorithm stalls when it runs into a cycle.

Frans Bouma | Lead developer LLBLGen Pro
kievBug
User
Posts: 105
Joined: 09-Jan-2009
# Posted on: 16-May-2013 15:54:37   

Not sure what is the problem with a model and having a nullable FK, and what can be changed in it so that it is better.

If there is a cycle in the graph, we remove all the optional dependencies(the relation with nullable field) and insert the data, after that we update those which are optional, basically the same way as developer would do in this case.

For us it works fine, and I just thought that it might be part of the library. I agree that it should be stable and doesn't bring any problems, confusion to get the library. So I'd say give a thought, try it, and if it works for you try to add it, IMHO it would definitely be a benefit :-)

Anton

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 17-May-2013 10:39:42   

kievBug wrote:

Not sure what is the problem with a model and having a nullable FK, and what can be changed in it so that it is better.

the problem is with the FK constraint. The model might change in that the nullability of the FK is no longer allowed: this will make the model impossible to be used. The cycle in the dependencies also give a problem with which follows what. You can model this away by introducing a new entity which models the relationships between the two.

If there is a cycle in the graph, we remove all the optional dependencies(the relation with nullable field) and insert the data, after that we update those which are optional, basically the same way as developer would do in this case.

For us it works fine, and I just thought that it might be part of the library. I agree that it should be stable and doesn't bring any problems, confusion to get the library. So I'd say give a thought, try it, and if it works for you try to add it, IMHO it would definitely be a benefit :-) Anton

We'll keep it in mind simple_smile

Frans Bouma | Lead developer LLBLGen Pro