Partager via


Tip 18 – How to decide on a lifetime for your ObjectContext

One of the most common questions we get is how long should an ObjectContext should live. Options often cited include one per:

  • Function
  • Form
  • Thread
  • Application

Plenty of people are asking these types of questions, case in point here is a question on Stackflow. I am sure there are many more buried away on our forums too.

This is a classic it depends type of question.

Lots of factors weigh into the decision including:

  • Disposal:
    Cleanly disposing of the ObjectContext and it’s resources is important. It is also significantly easier if you create a new ObjectContext for each Function, because then you can simply write a using block to ensure resources are disposed appropriately:

using (MyContext ctx = new MyContext())
{

}

  • Cost Of Construction:
    Some people are, quite understandably, concerned about the cost of recreating the ObjectContext again and again. The reality is this cost is actually pretty low, because mostly it simply involves copying, by reference, metadata from a global cache into the new ObjectContext. Generally I don’t think this cost is worth worrying about, but as always, there will be exceptions to that rule.
  • Memory Usage:
    The more you use an ObjectContext, generally the bigger it gets. This is because it holds a reference to all the Entities it has ever known about, essentially whatever you have queried, added or attached. So you should reconsider sharing the same ObjectContext indefinitely. There are some exceptions to that rule and a workaround, but for the most part these approaches just aren’t recommended.
    • If your ObjectContext only ever does NoTracking queries then it won’t get bigger because the ObjectContext immediately forgets about these entities.
    • You could implement some very explicit tidy-up logic, i.e. implement some sort of Recycle interface, that iterates through the ObjectStateManager detaching entities and AcceptingChanges(..) to discard deleted objects. Note: I’m not recommending this, I’m just saying it should be possible, I have no idea if relative to recreation it will result in any savings. So this might be a good subject for a future blog post. 
  • Thread Safety:
    If you are trying to re-use an ObjectContext you should be aware that is not thread safe, i.e. similar to the standard .NET collection classes. If you access it from many threads (e.g. web requests) you will need to insure that you synchronize access manually.
  • Stateless:
    If your services are designed to be stateless, as most web services should be, re-using an ObjectContext between requests might not be best because, the leftovers in the ObjectContext from the last call may have subtle effects on your application that you are not expecting.
  • Natural finite lifetimes:
    If you have a natural finite lifetime way of managing an ObjectContext,such as a short lived Form, a UnitOfWork or a Repository, then scoping the ObjectContext accordingly might be the best thing to do.

As you can see there are lots of issues at play.

Most of them tend to point towards a short lived context that isn’t shared.

So that is my recommended rule of thumb.

However as always understanding the reasoning behind a ‘rule of thumb’ will help you know when it is appropriate to go your way.

Comments

  • Anonymous
    May 07, 2009
    PingBack from http://blogs.msdn.com/alexj/archive/2009/03/26/index-of-tips.aspx
  • Anonymous
    May 08, 2009
    Another plus of reusing the same entity context across the application is that you need to load something like Products only once into memory across all requests instead of fetching Products each time the page is loaded by a user.Personally though, I prefer disposing the context as soon as I'm done with it because of the 'Stateless' reason you mention and ran into some issues with it a while back.As the EF matures I hope to see the recommendation shift towards creating a global entity context because it seems a lot more efficient.
  • Anonymous
    May 19, 2009
    This is 20th post in my ongoing series of Entity Framework Tips . Fixed Length Field Padding: If you
  • Anonymous
    June 09, 2009
    I like the idea of a "using" block to clean up. However, if one creates the ObjectContext in a method that returns an Entity (or IQueryable) retrieved by that ObjectContext, then one cannot use a "usings" block for the ObjectContext creation because at the caller side it complains (such as during GridView.DataBind). What then?
  • Anonymous
    June 09, 2009
    @Mark,You definitely shouldn't return something unenumerated from a using block.generally I do things like this psuedo code:using (ctx){  return Query.ToArray();}Now if you need to load relationships later, for example your query returns a customer, and you know you need to enumerate the Orders, if your ctx has been disposed (because of the using block) it won't work either.In that situation you should eagerly load what you need... i.e.using (ctx){  var Query = ...;  Query.Include("Orders");  return Query.ToArray();}Hope this helpsAlex
  • Anonymous
    June 19, 2009
    This is 20th post in my ongoing series of Entity Framework Tips . Fixed Length Field Padding: If you
  • Anonymous
    October 11, 2009
    The reason I use the context as a private class variable is that I have to change the entities outside my repository. So if I return an object and dispose its context. Then I can't change its properties, and send it back to get saved. I then have to manually serialize the entity before I send it to the repository, or I will get the "This entity is associated with another context"-error.Maybe I'm missing something here, but I would think this is the main reason to use the context as a private class variable. Because then you just implement IDisposable in your repository, and use the using pattern where the repository is used instead.
  • Anonymous
    October 12, 2009
    Moe,I don't think you are missing anything. Quite the contrary, what you describe sounds completely reasonable, maybe even a best practice.Alex
  • Anonymous
    November 04, 2009
    My problem is that I tried to keep my context around in Session for the same reasons Moe described above.  At login, I would retrieve some information and the user would manipulate that information.  Then, since I had the context in Session, I could simply update the object, and save the changes.This worked great until I tried to change to SQL Server Session State.....context cannot be serialized.  BOOM!  I'm done.Now I need to change all my data access pieces to run more stateless, which I understand the importance.  I was hoping that I could use the new .NET RIA Services, but that's really only for Silverlight.
  • Anonymous
    July 01, 2010
    Nice article.  Reassuringly, some of the suggests are conclusions I had already come to but some other nice reassurances like the fact that contructing the ObjectContext (with using(ctx) { ... }) isn't have on the system.  I was worried about that.  Thanks
  • Anonymous
    July 29, 2010
    Thanks for clarifying the cost of creating the ObjectContext.
  • Anonymous
    May 08, 2012
    Would there ever be a situation where using a class scoped context and a method scoped context would be a good idea?For example if you are returning and IQueryable of users where the data will be further processed, you would not want to destroy the context so you would use the class scoped. Then if you are preforming an add you could just put it in, save the changes and go on with life.public class UserRepository: IRepository<user>{       private ColoDatabase staticDB = new ColoDatabase();       public IQueryable<user> GetList()       {               return staticDB.users;       }       public Boolean Add(ref user item)       {           using (ColoDatabase db = new ColoDatabase())           {               item.id = db.users.Select(x => x.id).OrderByDescending(x => x).First() + 1;               db.users.AddObject(item);               var changes = db.SaveChanges();               return changes > 0;           }       }}This though could create issues where the method scoped context could add a user and it would not be reflected in the class scoped context. Thoughts?Love the post though, really good to see other people are concerned with best practices.Matthew