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: entity.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.

If you use a prefetch path to read a Customer and its related Order entities from the database, the Orders will not be re-loaded if you access the property after the fetch. A prefetch path which loads related entities makes sure that lazy loading will not undo the work the prefetch path already performed.

When the related entity is not found in the database, for example Customer has an optional relation with Address using Customer.VisitingAddressID - Address.AddressID and myCustomer.VisitingAddress is accessed and myCustomer doesn't have a related visiting address entity, by default the generated code will return a new, empty entity, in this case a new AddressEntity instance.

You can then test the Fields.State value of the returned entity, if it is a new entity or a fetched entity (by comparing the Fields.State property with EntityState.New for a new entity or EntityState.Fetched for a fetched entity).

You can tell the entity to return null (C#) or Nothing (VB.NET) instead of a new entity if the entity is not found by setting the property FieldMappedOnRelationReturnNewIfNotFound to false. In our example of the Customer and its optional VisitingAddress field, mapped on the relation Customer.VisitingAddressID - Address.AddressID, Customer will have a property VisitingAddressReturnNewIfNotFound. Setting this property to false will make myCustomer.VisitingAddress return null (C#) or Nothing (VB.NET) if the related Address entity is not found for myCustomer.

By default these properties are set to true, to avoid code breakage with existing code already in production. You can change this default in the LLBLGen Pro designer: in the project settings, change the project setting, in the LLBLGen Pro Runtime Framework subsection, LazyLoadingWithoutResultReturnsNew to false and re-generate your code. The code generator will now generate 'false' / False' for all FieldMappedOnRelationReturnNewIfNotFound flags in all entities which will make sure that if an entity doesn't exist, null / Nothing is returned instead of a new entity.

Info

Be aware that some code can trigger lazy loading while you didn't intent to. Consider Customer and Order which have an 1:n relation (and Order and Customer have a m:1 relation). The following code triggers the fetch of all orders for the myCustomer instance, while that wasn't the intention:

myCustomer.Orders.Add(myOrder);

while this code:

myOrder.Customer = myCustomer; 

does the same thing, as LLBLGen Pro keeps both sides of a relation in sync, however this line of code doesn't trigger lazy loading.

How to switch off lazy loading completely

Lazy loading isn't without downsides, e.g. the SELECT N+1 problem is a real issue with lazy loading where related data is fetched unintented, e.g. in a loop. It might therefore be beneficial to switch off lazy loading completely to avoid running into the downsides of lazy loading.

You can do that by setting the global boolean property EntityBase.EnableLazyLoading to false. By default this property is set to true for backwards compatibility (as lazy loading is on by default in SelfServicing). Setting the properties entity.AlwaysFetchFieldMappedOnRelation, e.g. myOrder.AlwaysFetchCustomer to true will override this setting. Also passing true for forceFetch in the methods which implement the lazy loading feature, the entity.GetSingle/MultiNavigator methods will override this global property.

If you have the setting LazyLoadingWithoutResultReturnsNew set to true in the LLBLGen Pro Runtime Framework settings in the designer, the property EntityBase.EnableLazyLoading controls the fetch of related data only. So when the property EntityBase.EnableLazyLoading is set to false (so no lazy loading occurs), accessing a navigator property, e.g. myOrder.Customer, still returns a new entity if the setting LazyLoadingWithoutResultReturnsNew is set to true.