locked
Access parent entity after context disposed RRS feed

  • Question

  • Hi there,

    I have a 1-to-many relationship between Company and Person in DB and generated Entity Framework proxies.

    If I do "from p in db.People select p" I can then iterate through people and call person.Company to get the related company object. This is all happening within a "using" block, so once done, the context gets disposed.

    However, inside the foreach loop, I need to pass the person object to another method, which does things to it later (e.g. on another thread), after the context has been disposed. If that method calls person.Company, I get "The ObjectContext instance has been disposed and can no longer be used for operations that require a connection."

    Is there a way to make an entity persist its parents?

    I've tried using Include as follows but it didn't make a difference, perhaps because Include only works when you're loading related child objects, not the parents.

    from p in db.People.Include("Company") select p

     


    • Edited by DashNYC Friday, August 26, 2011 6:26 PM it's => its grammar
    Friday, August 26, 2011 6:04 PM

Answers

  • Thanks Fernandoo for that example.  I think Fernando's method would work, but could you also just detach the objects from the context?  Such as DbEntities.Detach(p.Company) and DbEntities.Detach(p).  Then, reattach them to a new context in a method in another thread?  Then, you don't have to worry about creating another outside variable.    


    Tom Overton
    • Marked as answer by DashNYC Sunday, August 28, 2011 11:50 PM
    Friday, August 26, 2011 9:08 PM
  • Hi DashNYC;

    As Tom stated in his post you can detach the Person entity from the object context but you will also need to attach its Company entity back after the Detach as stated in my comments in the code snippet.

    This is how you could change the foreach loop to do it with the detach method.

    foreach(var p in query)
    {
     // Get a reference to the Company entity
     Company c = p.Company;
     // Then Detach the Person entity
     db.Detach(p);
     // Attach the Company entity to the Person entity because as stated in documentation
     // Only the entity is removed; if there are any related objects that are being tracked
     // by the same ObjectStateManager, those will not be detached automatically.
     p.Company = c;
     // Make the call to the AnotherMethod sending the Person entity as a parameter
     AnotherMethod(p);
     // ...
    }
    

     


    Fernando (MCSD)

    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".
    • Marked as answer by DashNYC Sunday, August 28, 2011 11:50 PM
    Saturday, August 27, 2011 1:49 PM

All replies

  • Dash,

    I'm thinking you should probably try to expand the lifetime of your ObjectContext and not use a using block inside your method.  You will need to make sure to manually dispose of your ObjectContext when you aren't using it anymore.  Or maybe create a central repository class of some type that will handle the create and dispose (which should implement IDisposable itself that then disposes of the context) and you can keep around as long as you need.  Is this a web application?  If so, you should probably do something like create the ObjectContext in the BeginRequest event and dispose of it in the EndRequest event. 

     


    Tom Overton

    Friday, August 26, 2011 6:26 PM
  • Hi Tom,

    Thanks for the reply. I'd prefer not to extend the lifetime of the context since it'd make the code very messy and error prone. I'm writing a Windows Service and I need to get the data, disconnect from DB, and later read the data objects on a different thread. ObjectContext is not thread-safe, so I'd rather not share it accross multiple theads. Since I'm only reading the objects (not editing), I don't want to do any locking.

    I think one way to approach this problem would be to use projection

    from p in db.People select new MyPersonWrapper { Person = p, Company = p.Company }

    Still I'm wondering if there is a more elegant way using Entity Framework's features alone.

     

    Friday, August 26, 2011 6:48 PM
  • Dash,

    I guess what you will have to do is create a new ObjectContext for the new thread , and attach your object to it.  If you do that you will have to detach the object from the original ObjectContext and therefore lose lazy loading and change tracking but maybe that is okay for what you are doing.


    Tom Overton
    Friday, August 26, 2011 7:32 PM
  • Hi DashNYC;

    You should be able to do what you need doing something like the following.

    Person person = null;
    
    using( DbEntities db = new DbEntities( ) )
    {
      var query from p in db.People 
           select p;
           
      foreach(var p in query)
      {
        // do somthing with p and if p will be one of the Person 
        // entities to be used out side the using statement first
        // make sure to access one the Company fields and then assign the 
        // Person entity to a variable outside the using statement
        person = p;    
      }
    }
    

    Let me know if that helped.

    Hay, stay safe up in New York City with Irene on her way up, I feel for you all.

     


    Fernando (MCSD)

    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".
    Friday, August 26, 2011 8:14 PM
  • Thanks Fernandoo for that example.  I think Fernando's method would work, but could you also just detach the objects from the context?  Such as DbEntities.Detach(p.Company) and DbEntities.Detach(p).  Then, reattach them to a new context in a method in another thread?  Then, you don't have to worry about creating another outside variable.    


    Tom Overton
    • Marked as answer by DashNYC Sunday, August 28, 2011 11:50 PM
    Friday, August 26, 2011 9:08 PM
  • Hi DashNYC;

    As Tom stated in his post you can detach the Person entity from the object context but you will also need to attach its Company entity back after the Detach as stated in my comments in the code snippet.

    This is how you could change the foreach loop to do it with the detach method.

    foreach(var p in query)
    {
     // Get a reference to the Company entity
     Company c = p.Company;
     // Then Detach the Person entity
     db.Detach(p);
     // Attach the Company entity to the Person entity because as stated in documentation
     // Only the entity is removed; if there are any related objects that are being tracked
     // by the same ObjectStateManager, those will not be detached automatically.
     p.Company = c;
     // Make the call to the AnotherMethod sending the Person entity as a parameter
     AnotherMethod(p);
     // ...
    }
    

     


    Fernando (MCSD)

    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".
    • Marked as answer by DashNYC Sunday, August 28, 2011 11:50 PM
    Saturday, August 27, 2011 1:49 PM