Click here to Skip to main content
15,891,136 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
I am learning EF. While practicing I noticed a strange behavior for Lazy Loading.

I read, Lazy loading is enabled by default and can work only if navigation properties are marked virtual along with LazyLoadingEnabled = ture in context's configuration.
So, I decided to turn off lazy loading by setting the switch to off i.e., LazyLoadingEnabled = false.

Here is the code that tried to access the dbset after then:
if (context == null)
         context = new InventoryEntities(".");
     context.Configuration.LazyLoadingEnabled = false;
     List<STOCK_ITEM_GROUPS> res = (from groups in context.STOCK_ITEM_GROUPS
                                  orderby groups.name
                                  select groups).ToList<STOCK_ITEM_GROUPS>();           
           string msg = "";
           foreach (var groups in res)
               msg += "Name: " + groups.name + "\tParent Name: " +                 (groups.STOCK_ITEM_GROUPS2 == null ? "none" : groups.STOCK_ITEM_GROUPS2.name) + Environment.NewLine;
              
           Console.WriteLine(msg);


Below is the dbset generated for STOCK_ITEM_GROUPS:
public partial class STOCK_ITEM_GROUPS
    {
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
        public STOCK_ITEM_GROUPS()
        {
            this.STOCK_ITEM_GROUPS1 = new HashSet<STOCK_ITEM_GROUPS>();
            this.STOCK_ITEM_MASTER = new HashSet<STOCK_ITEM_MASTER>();
        }
    
        public short id { get; set; }
        public string name { get; set; }
        public Nullable<short> idParent { get; set; }
        public bool itemAddable { get; set; }
        public bool isactive { get; set; }
        public System.DateTime active_timestamp { get; set; }
        public Nullable<System.DateTime> deactivation_timestamp { get; set; }
        public byte[] rv { get; set; }
    
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
        public virtual ICollection<STOCK_ITEM_GROUPS> STOCK_ITEM_GROUPS1 { get; set; }
        public virtual STOCK_ITEM_GROUPS STOCK_ITEM_GROUPS2 { get; set; }
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
        public virtual ICollection<STOCK_ITEM_MASTER> STOCK_ITEM_MASTER { get; set; }
    }


Now, ideally I should not receive data for navigation property
public virtual STOCK_ITEM_GROUPS STOCK_ITEM_GROUPS2 { get; set; }
, since, lazy loading is not enabled. But, I am receiving the related data!
I tried turning lazy loading off in the context's constructor as well but no help.

I might be missing any conceptual thing or there is something else I dont really know.
Looking at debugger for queries generated, I find only one query that looks for all the data from database.
thus, there are not multiple queries too but there is the related data. I dont understand where I am going wrong.

What I have tried:

I tried the same with Load() method on DbSet, it also returns same result as ToList() returns.
Searched on google but found only 1 comment, which is not really the condition I am in, here is the link for that:
c# - Entity Framework - Lazy Loading working even with ToList() - Stack Overflow[^]
Posted
Updated 9-Mar-17 6:40am
v2

I suspect that this is because you're using self-referencing navigation properties, and loading the entire set into memory.

I can't find the equivalent documentation for EF6, but the EF Core documentation has a note that would explain this behaviour:
Entity Framework Core will automatically fix-up navigation properties to any other entities that were previously loaded into the context instance. So even if you don't explicitly include the data for a navigation property, the property may still be populated if some or all of the related entities were previously loaded.

If you look at the STOCK_ITEM_MASTER collection instead, it should not be loaded automatically.
 
Share this answer
 
Comments
Member 11040029 10-Mar-17 0:52am    
Exactly Richard! that's what is happening. Thnx for this.
And I was clicking on 5th start, accidentally clicked on 4th..sorry :)
Disabling lazy loading doesn't stop related data loading, it stops it being loaded on-demand, so instead it is loaded right away. You might be better using the "Include" feature to dictate what data is lazy-loaded or not on a per-case basis. It will make it explicit what is being lazy loaded and what isn't.
 
Share this answer
 
Comments
Member 11040029 8-Mar-17 10:01am    
I am not sure with your answer f-ES, it sounds completely opposite to what I have learnt from books and web. Diabling lazy loading doesn't load related data at all. This must be the case. Using Include, is the explicit loading that one can perform. Its the choice.
And, if Disabling lazy loading doesn't stop related data loading, then one will run into damm big problem with just thousand record with related data in many tables for daily transactions say. I am sure MS guys kept this thing in mind while constructing the framework.
I am sorry, but the first sentence you mentioned is completely contradictory to the concept of related data loading.
If related data loads everytime inspite of disabling Lazy Loading, then imagine what will happen. I believe EF will not be of much use.

Please correct me F-ES, if I understood your answer wrong?
F-ES Sitecore 8-Mar-17 10:16am    
I said disabling lazy loading stops the data loading on-demand and instead loads the data right away. With lazy loading

customer.Firstname -> only customer data is used, no other data loaded
customer.Orders.First().OrderNumber -> at this point the Orders data is loaded

Without lazy loading

customer.Firstname -> the Orders data has already been loaded and is there to use if you use it or not
customer.Orders.First().OrderNumber -> the Orders collection is already populated so there is no db access here
Member 11040029 9-Mar-17 0:33am    
(customer.Firstname -> only customer data is used, no other data loaded)..that is what I am trying to say..At this point only, while debugging, I found (customer.Orders.First().OrderNumber)data is loaded too!

F-ES Sitecore 9-Mar-17 4:12am    
When you access those properties for debugging they are loaded by EF. Accessing the data for debugging is no different than accessing it in your code. To debug what EF is doing you have to use SQL Profiler. That will show you when EF is making DB requests and what it is requesting.
Richard Deeming 9-Mar-17 12:28pm    
This MSDN page[^] seems to contradict your answer.

"Lazy loading can be turned off for all entities in the context by setting a flag on the Configuration property. ... Loading of related entities can still be achieved using eager loading (see Eagerly Loading above) or the Load method (see Explicitly Loading below)."

That suggests that EF only eagerly loads the related data when you use the Include method; otherwise, the navigation property collections should remain empty.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900