Entity Framework Lazy Loading by Context or by Property?

When Entity Framework finally brought in support for Lazy Loading, there were still complaints. The lazy loading in EF4 is context based, not property based as defined by some of the other ORMs. (I’m not sure which ones or how many.)

I was thinking about this today and realized that EF does, in fact, support property level lazy loading.

There are three essential types of entities in EF4 –

  1. EntityObjects
  2. POCOs that lean on dynamic proxies at runtime
  3. POCOs that depend on EF’s snapshot notification

The POCOs that use dynamic proxies can do so only when every single property is marked virtual. Then they benefit from the same notification behavior at runtime as do EntityObjects and they benefit from lazy loading.

Simple POCOs that do not use dynamic proxies can still benefit from lazy loading. As long as the relationship property is marked virtual and additionally, properties that point to collections have to be a collection type that implements ICollection, the property will be loaded on demand (when the context’s lazy loading is enabled).

In this last case (the simple POCOs), you can pick and choose which of the relationship properties are able to lazy load. Then with the context set to LazyLoadingEnabled=true, lazy loading will occur, but only for the properties you have specified.

Now, I’m not sure how this compares to those other ORMs whose users criticized the context-level lazy loading, but it feels like it might be a lot closer then they realized. And I’m absolutely interested in finding out if I’m on the right track or completely off base (in which case I can only ask: “be gentle” 🙂 ).

  Sign up for my newsletter so you don't miss my conference & Pluralsight course announcements!  

9 thoughts on “Entity Framework Lazy Loading by Context or by Property?

  1. I’ve tried this using the T4 generated POCO’s for RC1 and it doesn’t seem to work for me. Maybe I’m misunderstanding how it’s supposed to work, but I was assuming that simply accessing a property that returned a (non loaded) collection would trigger the collection to be populated?

  2. You asked about how others do it.

    In DevForce (http://www.ideablade.com), the generated entities have lazy loading navigation (aka Relationship) properties by default; you can subsequently change the behavior of any navigation property of any type by programmatic configuration of your model. You can turn it on and off at will.

    That flexibility might be important if you wanted to deploy the same model in different environments and want different behavior (lazy or not) according to that environment.

    Thus lazy might be good in 2-tier, smart client but not cool on the server, or in Silverlight, or backing an ASP web client.

    Of course with our POCOs you do as you wish.

    Pure FYI.

  3. Hi Julie.

    I’ll try to "be gentle" 🙂 but I think you’re slightly off track here.

    As far as I can tell (and test) you can’t automatically get lazy loading (or loading at all) on your relationship properties when using simple POCO’s without proxies.

    The reason for this is that ObjectContext doesn’t automatically map/fill in your relationship properties through your ObjectContext.ObjectSet<T> properties and since the returned object is your plain POCO then the relationship property is simply empty and returned as such the first time you ask for it – and your ObjectContext isn’t actually involved at all when asking for the property on your plain POCO.

    The only way that I’ve found to actually load your relationship properties is to do it explicitly yourself as in:

    context.LoadProperty(myOjbect, c => c.MyRelProperty)

    Looking forward to hear your comments – I would love to be wrong! 🙂

    – Best regards, Jakob

  4. Hi,

    I have recently been given a project that was constructed in MS MVC 2.0 and Entity 4. I was having the same problems as Jakob, that all of my object properties WOULD NOT Lazy Load. The only way that I was able to get them to add the properties was through explicit commands…

    Context.LoadProperty

    Or

    context.Orders.Include("OrderDetails")

    Then I discovered its partly the choices of which EntityObject you use, and if the proxy class creation was turned on or not. If the Proxy class is off, then it doesn’t matter what method you try, Lazy Loading simply doesn’t work.

  5. Steve and Jakob

    It works 100%. I even just went back to my previous code and double checked.

    Don’t forget that you must have ObjectContext.ContextOptions.LazyLoadingEnabled=true somewhere. By default with code gen’d entities, it’s in the ctors for the context. That’s where I put it in my hand written objectContext class.

    Julie

  6. Hi Julie,

    Thanks for your reply. I’ve doublechecked my code as well and I still can’t make it work. I already have

    ObjectContext.ContextOptions.LazyLoadingEnabled = true

    but I also have

    ObjectContext.ContextOptions.ProxyCreationEnabled = false

    so are we still talking about the same thing here: "Simple POCOs that do not use dynamic proxies can still benefit from lazy loading"?

    I even tried

    ObjectContext.Departments.Include("Manager") as Steve suggested, but I can only make my relationship properties load when doing it explicitly:

    ObjectContext.LoadProperty(dep, "Manager").

    – Jakob

  7. Jakob

    I think the problem is that you are disabling the off proxy creation.

    I’ll have to experiment myself (or you can do this same) but the context needs to do some proxy work in order to get the lazy loading. If you don’t have the other properties marked virtual then you won’t get the change tracking.

    What will be interesting to see in the debugger is the differnece between what the instantiated object looks like when you’ve marked ALL properties as virtual vs. when you’ve marked just the desired navigatoin properties virtual to get lazy loading.

    Just curious why you are explicitly turning off dynamic proxy creation? the only time I ever use that is if it’s a wcf service operation and I’m returning data and you are using dynamic proxies. I turn it off just before returning the data or it wreaks havoc. But in that case you don’t want lazy loading anyway. I also turn off lazy loading. If ll is on when you serialize you’ll bring back the whole darned database (I’m exaggerating but it’s pretty bad).

    julie

  8. Hi Julie,

    I’m turning off the proxy creation to experiment with simple POCOs without proxies. Not yet sure if I need to go that way, but we are implementing a Domain Driven Design approach and the runtime proxies feels a bit akward in that context. I can’t say I have any strong arguments (yet), it’s more a gut feeling…

    Another reason is regarding the design of my POCOs: If I HAVE TO mark all my properties virtual, then it’s really not pure POCO/DDD, since I’m constrained to a certain design. Again, it’s more a gut feeling and maybe I’ve just started a pseudo debate…?

    I’ve done some experiments as you mentioned (having lazy loading enabled on the ObjectContext):

    1) All properties marked as virtual on BOTH classes

    = proxy creation of originating instance + automatic loading of navigation property as proxy instance

    2) All properties marked as virtual on originating class + 1 or more properties NOT marked as virtual on navigation class

    = proxy creation of originating instance + automatic loading of navigation property as POCO instance

    3) Only navigation property marked as virtual on originating class + 1 or more properties NOT marked as virtual on navigation class

    = proxy creation of originating instance + automatic loading of navigation property as POCO instance

    4) Navigation property NOT marked as virtual on originating class + 1 or more properties NOT marked as virtual on navigation class

    = POCO creation of originating instance + NO automatic loading of navigation property

    Jakob

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.