SelfServicing related entity properties fetch on every access

Posts   
 
    
Posts: 48
Joined: 14-Feb-2008
# Posted on: 14-Jul-2010 17:16:45   

Hi!

I'm using LLBL 2.5 on SQL Server 2005.

Upon accessing a property, not accessed before, that holds a related entity, SelfServicing code will try to fetch the proper related entity. If it fails, it creates a new entity and returns that. I'm ok with all this.

However, I've noticed that in a piece of code that goes something like this:

entityA.entityBviaId.foo = 1;
entityA.entityBviaId.bar = 2;

the fetch gets performed every time I access the entity, which I can confirm in the trace output. In this particular case it would be performed twice. Also, when I save ( by entityA.Save(true) ) the entityB gets only the last field, "bar", set.

Apparently, each time I access the lazy-loaded entity, the code tries to fetch it, fails (which is ok, there is no such entity in the DB), and each time creates and returns a brand new entity.

If it's of importance, the relation in question is 1:1.

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 15-Jul-2010 04:52:21   

Please check the value of EntityA.AlwaysFetchEntityBviaId, it should be false otherwise it will try to fetch the related property each time.

David Elizondo | LLBLGen Support Team
Posts: 48
Joined: 14-Feb-2008
# Posted on: 15-Jul-2010 10:18:36   

The value of the flag is false. I've just stepped through the method, and it did not change. Interesting thing is that due to the fact I had the entityA displayed in the debugger's watch window, two select statements were executed every time I'd switch focus to Visual Studio.

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 15-Jul-2010 10:24:44   

Which runtime library version(build number) are you using?

Posts: 48
Joined: 14-Feb-2008
# Posted on: 15-Jul-2010 10:29:02   

SD.LLBLGen.Pro.ORMSupportClasses.NET20.dll has the version 2.5.8.618 (got it through the standard windows properties dialog, if that matters).

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 15-Jul-2010 10:59:52   

Are you sure these SQL queries got executed (sent) to the database?

Posts: 48
Joined: 14-Feb-2008
# Posted on: 15-Jul-2010 11:07:05   

Well, no.

I am sure the trace output says a method "CreateSelectDQ" generates the SQL queries, then, after each, DaoBase.ExecuteSingleRowRetrievalQuery is called, and all within DaoBase.PerformEntityFetchAction. And of course, there's the fact that any changes I make to the entity get lost, and are not saved to the DB at the end of the process...

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 15-Jul-2010 11:37:09   

I am sure the trace output says a method "CreateSelectDQ" generates the SQL queries, then, after each, DaoBase.ExecuteSingleRowRetrievalQuery is called, and all within DaoBase.PerformEntityFetchAction. And of course, there's the fact that any changes I make to the entity get lost, and are not saved to the DB at the end of the process...

That's enough evidence I guess.

PLease check the following documentation note, and check if you are forcing the fetch by any of the means mentioned.

Load on demand/Lazy loading

Once loaded, the entity is not loaded again, if you access the property again. This is called load on demand or lazy loading: the load action of the related entity (in our example 'customer') is done when you ask for it, not when the referencing entity (in our example 'order') is loaded. You can set a flag which makes the code load the related entity each time you access the property: AlwaysFetchFieldMappedOnRelation. In our example of Order and Customer, OrderEntity has a property called AlwaysFetchCustomer and CustomerEntity has a property called AlwaysFetchOrders. Default for these properties is 'false'. Setting these properties to true, will assure that the related entity is reloaded from the database each time you access the property. This can be handy if you want to stay up to date with the related entity state in the database. It can degrade performance, so use the property with care.

Another way to force loading of a related entity or collection is by specifying true for the forceFetch parameter in the GetSingleFieldMappedOnRelation call, or when the property contains a collection, GetMultiFieldMappedOnRelation call. Forcing a fetch has a difference with AlwaysFetchFieldMappedOnRelation in that a forced fetch will clear the collection first, while AlwaysFetchFieldMappedOnRelation does not. A forced fetch will thus remove new entities added to the collection from that collection as these are not yet stored in the database.

Posts: 48
Joined: 14-Feb-2008
# Posted on: 15-Jul-2010 11:55:02   

Nope, I haven't meddled with any flags, or used any other means to fetch the entities than simply using the constructor that takes the PK value as it's argument for entityA (could the problem be related to that?), and using the generated property for accessing entityB.

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 15-Jul-2010 12:00:12   

Could you please send us (attach), a simple repro solution using Northwind database.

Posts: 48
Joined: 14-Feb-2008
# Posted on: 15-Jul-2010 12:20:15   

Not right now, I'm kinda busy. Maybe tomorrow.

There's another thing that's maybe interesting - we change the configuration of the code generator to generate property names different than the default.

Namely, since we had many cases where a single entity would reference a user data entity several times (created by, last changed by, printed by,...), and LLBL would create relation properties with names "UserData", "UserData" and "UserData_" (two underscores...), we changed the configuration, setting "FieldMappedOnOneManyToOnePattern" to {$EndEntityName$S}Via{$StartEntityFieldNames}. This creates names like "UserDataViaCreatedById", "UserDataViaUserModifiedId" and so on.

In this particular case, EntityA has a generated property named EntityBViaId. EntityB has a field EntityAId. That field is his primary key, and at the same time a foreign key pointed at EntityA.Id.

MTrinder
User
Posts: 1461
Joined: 08-Oct-2008
# Posted on: 16-Jul-2010 01:49:12   

The behaviour you describe is possible using 2.5 as it did not have protection against it. If it is causing you an issue, would it be possible for you to upgrade to 2.6, as 2.5 is now several years old.

Otherwise, a workaround would be something like


EntityBEntity entityB = entityA.EntityBviaId;
entityBviaId.foo = 1;
entityBviaId.bar = 2;

which should only cause the related entity to be fetched once.

Matt

Posts: 48
Joined: 14-Feb-2008
# Posted on: 16-Jul-2010 09:35:26   

I'm now avoiding use of the related properties altogether, and fetching all the entities myself. But your proposal is better, since if I do it your way, I'll still be able to do a recursive save, and avoid having to manually open a transaction, correct?

So, the conclusion is that this is a known issue with 2.5, and the solution is upgrading to 2.6?

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 16-Jul-2010 09:40:22   

So, the conclusion is that this is a known issue with 2.5, and the solution is upgrading to 2.6?

Yes.