New entity is not saved when added to a collection

Posts   
 
    
kievBug
User
Posts: 105
Joined: 09-Jan-2009
# Posted on: 16-Sep-2014 21:17:15   

Hey guys,

I have this structure: MainEntity: ID - primary key, Caption - string field Relateds - 1:M collection of RelatedEntity

RelatedEntity: ID - primary key, Caption - string field MainID - foreign key to MainEntity.ID

Please note that RelatedEntity doesn't have a navigator for MainID. I'm trying to add new RelatedEntity into the collection of the new MainEntity and it fails with an error that the MainID field is not set. I'm not sure if it is a bug or a by design behaviour?


                var main = new MainEntity
                {
                    Caption = "rec 1",
                };

                main.Relateds.Add(new RelatedEntity
                {
                    Caption = "Related rec 1",
                });

                main.Relateds.Add(new RelatedEntity
                {
                    Caption = "Related rec 2",
                });

                adapter.SaveEntity(main);

I'm using LLBLgen 3.1, SQL Server, Adapter.

Thanks, Anton

Walaa avatar
Walaa
Support Team
Posts: 14946
Joined: 21-Aug-2005
# Posted on: 16-Sep-2014 23:27:13   

Isn't this a cyclic reference? Why do you need a reference from the RelatedEntity back to the MainEntity?

kievBug
User
Posts: 105
Joined: 09-Jan-2009
# Posted on: 16-Sep-2014 23:34:42   

This a regular 1:m between main and related. It has just one navigator on the MainEntity side but doesn't have a navigator on the RelatedEntity side. There is no cyclic reference there is just one foreign key.

Anton

Walaa avatar
Walaa
Support Team
Posts: 14946
Joined: 21-Aug-2005
# Posted on: 17-Sep-2014 07:36:05   

Oh, my bad.

So I assume it's failing when saving to the database, correct? Is the MainEntity - ID an auto-generated/Sequence at the database side?

Also to save the related entities, you need to call the other overload of save entity, passing true for recurse.

SaveEntity(main, false, true);

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 17-Sep-2014 09:57:19   

kievBug wrote:

This a regular 1:m between main and related. It has just one navigator on the MainEntity side but doesn't have a navigator on the RelatedEntity side.

This is by design. If you have Customer.Orders 1:n Orders.<nothing>, 'Customer' is unknown for 'Order', as there's no navigator mapped onto the relationship, as there's no property in Order of type Customer (which would be the representation of the navigator).

In cases like this you have to manually set the FK field in the Related entity (Order in my example).

Frans Bouma | Lead developer LLBLGen Pro
kievBug
User
Posts: 105
Joined: 09-Jan-2009
# Posted on: 17-Sep-2014 15:11:17   

Hmm, it is really hard to do it manually, IMHO it would be much easier to implement on the framework level :-(

Anton

kievBug
User
Posts: 105
Joined: 09-Jan-2009
# Posted on: 17-Sep-2014 15:30:27   

Will it still determine the order of inserts correctly in this case?

Anton

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 17-Sep-2014 18:00:38   

kievBug wrote:

Hmm, it is really hard to do it manually, IMHO it would be much easier to implement on the framework level :-(

Anton

How would that be possible, if 'Order' doesn't have a reference to its customer? It can't reach the customer. That's the cause of the issue and why it won't work.

If you want this behavior, you have to enable the navigator on the FK side, that's documented. I'm not sure whether this is possible for your model, but it is required in the situation where you want pk/fk syncing and graph persistence.

kievBug wrote:

Will it still determine the order of inserts correctly in this case? Anton

Not necessarily as there's no reference from the FK side to the PK side, so the engine can't determine whether there's a dependency from the FK side to the PK side: the PK side is unknown to the FK side as far as the engine is concerned.

So unless your application breaks, it's best to enable the FK side navigator. Why did you remove that btw? Perhaps we can guide you to an alternative solution to the problem you tried to solve by removing the navigator simple_smile

Frans Bouma | Lead developer LLBLGen Pro
kievBug
User
Posts: 105
Joined: 09-Jan-2009
# Posted on: 17-Sep-2014 18:06:08   

And if I in the GetDependingRelatedEntities method for Customer will return Orders which depend on this customer - it seems it will fix the problem and will save entities in the correct order.

Anton

kievBug
User
Posts: 105
Joined: 09-Jan-2009
# Posted on: 17-Sep-2014 19:35:05   

Well, the thing is that user configures the model through the UI. User can create new entities at run-time and new fields too, and as a part of configuration user can also add or remove navigators. So if user doesn't need a navigator on the FK side, it is still a valid scenario, and my code has to work in this case even though LLBLGen doesn't support it. I'm using UnitOfWork to save changes and both Order and Customer records are added to the unit of work, both of them are new. Order is in the collection of Customer.Orders, and as for me it is possible to figure out such case that there is no navigator on the Order side and in this specific case still order the inserts correctly. I've put the code into the GetDependingRelatedEntities and it seems to work properly. I'm just not sure will it cause any problems or not, and why LLBLGen doesn't generate it by default in the templates if it finds this case.

Anton

Walaa avatar
Walaa
Support Team
Posts: 14946
Joined: 21-Aug-2005
# Posted on: 18-Sep-2014 03:21:32   

I'm just curious about the business case behind letting the user opt for a Navigator or not?

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 18-Sep-2014 10:20:35   

kievBug wrote:

I've put the code into the GetDependingRelatedEntities and it seems to work properly. I'm just not sure will it cause any problems or not, and why LLBLGen doesn't generate it by default in the templates if it finds this case.

To clarify: it doesn't do this as it doesn't know if you want this or not. The idea is that if you want graph persistence, you put in place the navigator. If the navigator isn't there, the only valid conclusion from that is to say: "the PK side is invisible from the FK side", which is a valid situation, e.g. when the FK side is cached and you don't want the PK side to stick around.

If you don't want the navigator to be public, you can make it internal in the designer. The navigator however has to be present, for fk/pk syncing purposes. The code you put in place works in graph persistence, but won't sync an FK field with its pk field.

As the FK field is present in the DB and the relationship present in the model, it's IMHO much easier to simply enable the navigator, as you want behavior as if the navigator is present. simple_smile

Frans Bouma | Lead developer LLBLGen Pro