locked
How lazy loading works when objectContext is already out of scope( not disposed) RRS feed

  • Question

  • How does lazy loading work when objectcontext is already out of scope(not disposed, if it is disposed, it will throw exception for sure)? 

    I call GetOrder()(shown in below) to get object Order, then want to access Order.Customer, it will automatically get customer object by lazy loading. Question here is:  ObjectContext reference is already out of scope. How does it work under the cover? Objectcontext is static or global variable sitting somewhere?   If I update Order, ObjectContext will still keep tracking of entity Order?

    anyone can shed light on what happens exactly behind the scenes?

     

    Entity framework 4.0, visual studio 2010 In multilayer application.

     

    For instance , I have following code:

      public static Order GetOrder()
            {
                Order order =null;
                 Repository rep = new Repository();
                {
                    order = rep.GetOrder(10250);
                    //rep.Dispose();
                }
                return order;           
            }

     

    Sunday, June 19, 2011 5:52 PM

Answers

  • Hi,

    When you (some way or another) gets an entity from your ObjectContext (Repository), the entity object automatically gets a reference far below in the code to the ObjectContext that it came from (More general speaking, the entity is attached to your ObjectContext). So, as long that you don't dispose your ObjectContext in your code manually, the ObjectContext will live as long as your entity (order) lives. And as long as it lives, you can use lazy loading to retrieve information from navigation properties on it.

    The ObjectContext connected to your entity will always keep track of it. But, since you don't have any reference to it in your code anymore, you can't persist it to your storage in any easy way. To do that you'll need to create a new context, attach the entity to this new context and call savechanges on this new context. But this imposes a problem, the entity is attached to a another ObjectContext, and a entity can only be connected to one ObjectContext at the time. So you will get an exception. The only way to don't get this is to detach the entity from the ObjectContext, but then again Lazy Loading won't work.

    So, this causes two different problem for you. If you want to use lazy loading, you can't persist changes, and if you want to be able to persist changes you need to detach it from the original ObjectContext before leaving GetOrder which disables Lazy loading.

    Dependent on your application structure there is a couple of ways to solve this.

    The easiest is to keep a reference to the ObjectContext, this will give you the opertunity to both lazy load and persist your entity. The problem with this is that an ObjectContext is designed to be a short lived object, if you keep it for long with lots of transactions against it, it will grow in size and aquire more and more resources.

    A second option is to use eager loading (that is, using Include(...)) and when you have retrieved your order, detaching it from the ObjectContext and return it. It can then easily be reattached to a another ObjectContext for persisting changes to your storage.

    I hope this answered some of your questions! Feel free to ask more if you want.


    --Rune
    Sunday, June 19, 2011 8:56 PM

All replies

  • Hi,

    When you (some way or another) gets an entity from your ObjectContext (Repository), the entity object automatically gets a reference far below in the code to the ObjectContext that it came from (More general speaking, the entity is attached to your ObjectContext). So, as long that you don't dispose your ObjectContext in your code manually, the ObjectContext will live as long as your entity (order) lives. And as long as it lives, you can use lazy loading to retrieve information from navigation properties on it.

    The ObjectContext connected to your entity will always keep track of it. But, since you don't have any reference to it in your code anymore, you can't persist it to your storage in any easy way. To do that you'll need to create a new context, attach the entity to this new context and call savechanges on this new context. But this imposes a problem, the entity is attached to a another ObjectContext, and a entity can only be connected to one ObjectContext at the time. So you will get an exception. The only way to don't get this is to detach the entity from the ObjectContext, but then again Lazy Loading won't work.

    So, this causes two different problem for you. If you want to use lazy loading, you can't persist changes, and if you want to be able to persist changes you need to detach it from the original ObjectContext before leaving GetOrder which disables Lazy loading.

    Dependent on your application structure there is a couple of ways to solve this.

    The easiest is to keep a reference to the ObjectContext, this will give you the opertunity to both lazy load and persist your entity. The problem with this is that an ObjectContext is designed to be a short lived object, if you keep it for long with lots of transactions against it, it will grow in size and aquire more and more resources.

    A second option is to use eager loading (that is, using Include(...)) and when you have retrieved your order, detaching it from the ObjectContext and return it. It can then easily be reattached to a another ObjectContext for persisting changes to your storage.

    I hope this answered some of your questions! Feel free to ask more if you want.


    --Rune
    Sunday, June 19, 2011 8:56 PM
  • Thanks, Rune.

    Since it is enterprise multilayer application, I use second option. Once I have retrieved data, I explicitly dispose objectContext instead of detaching from objectContext.

    Later, I use the following code to save changes.a

    public void Update(Order order)

    {

       string entitySetName = "Orders";

       EntityKey key = this.EFObjectContext.CreateEntityKey(entitySetName, order);

       Object oldEntry =null;

       This.EFObjectContext.TryGetObjectByKey(key, out oldEntry);

       this.EFObjectContext.Orders.ApplyCurrentValues(order);

    }

    Public void Save(Order order)

    {

         this.EFObjectContext.SaveChanges()

    }

     

    Monday, June 20, 2011 2:40 AM
  • Hi!

    Just a small note, it's not enough just to dispose the ObjectContext, you'll need to detach the entity to explict tell it that it shouldn't use the ObjectContext you're disposing anymore.


    --Rune
    Monday, June 20, 2011 5:11 AM
  • Rune,

    not sure why do we need to detach the entity after Objectcontext is disposed?  Aforementioned Update() and Save() code still work properly.

    To my understanding, we don't need to detach   entity after ObjectContext is disposed, unless If you want to attach the same entity to other new ObjectContext, is that correct?

     

    Thanks,

    Tuesday, June 21, 2011 10:46 AM
  • Yes, that's correct, you don't need to do it..

    But you need to be careful, and have your code as your last example when you want to persist data then, if you try to use the more standard Attach/AttachTo/Add/AddTo functions you'll get an error if you don't detach first.


    --Rune
    Tuesday, June 21, 2011 12:16 PM