13

I'm learning EF now and have a question regarding the ObjectContext:

Should I create instance of ObjectContext for every query (function) when I access the database?

Or it's better to create it once (singleton) and reuse it?

Before EF I was using enterprise library data access block and created instance of dataacess for DataAccess function...

verror
  • 349
  • 1
  • 3
  • 9
  • IMO - use DI to resolve the instance of the EF object context & play around with the lifetimes to check which option gives you the best results... – Sunny Apr 27 '10 at 19:07

6 Answers6

15

I think the most common way is to use it per request. Create it at the beginning, do what you need (most of the time these are operation that require common ObjectContext), dispose at the end. Most of DI frameworks support this scenario, but you can also use HttpModule to create context and place it in HttpContext.Current.Items. That is simple example:

public class MyEntitiesHttpModule : IHttpModule
{
    public void Init(HttpApplication application)
    {
        application.BeginRequest += ApplicationBeginRequest;
        application.EndRequest += ApplicationEndRequest;
    }

    private void ApplicationEndRequest(object sender, EventArgs e)
    {
        if (HttpContext.Current.Items[@"MyEntities"] != null)
            ((MyEntities)HttpContext.Current.Items[@"MyEntities"]).Dispose();
    }

    private static void ApplicationBeginRequest(Object source, EventArgs e)
    {
        var context = new MyEntities();
        HttpContext.Current.Items[@"MyEntities"] = context;
    }
}
LukLed
  • 31,452
  • 17
  • 82
  • 107
  • 1
    I think this is a less maintainable solution than simply creating an ObjectContext when you need one in the data layer. My objection against this solution is that you create a dependency between your UI layer and your data layer that isn't necessary. How you communicate with a database is an internal concern for the data layer. Second, it may seem easy at first to never have to worry about lazy-loading issues but some day you're trying to track down a bug and can't determine where it went wrong because you have no idea where the data that caused the bug was loaded (speaking from experience..) – Ronald Wildenberg Apr 27 '10 at 20:03
  • 1
    @rwwilden: Sorry, but how does it create dependency between UI and data layer? I am using repository pattern and repositories have to share context. Context is injected by DI container. Request is not that long and doesn't have so much operations that can cause so much problems. If you use proper patterns, you'll have no problems. – LukLed Apr 27 '10 at 20:23
  • 1
    @rwwilden: There were million questions about ObjectContext reusage, here on SO and other pages. Per request usage seems to dominate, it is not only my opinion. – LukLed Apr 27 '10 at 20:29
  • @LukLed About the dependency. Somewhere in your UI layer you have to say: new MyEntities(). The fact that you use entity framework for accessing data is an implementation detail of the data layer in my opinion. – Ronald Wildenberg Apr 28 '10 at 05:58
  • @LukLed I did a quick search on ObjectContext reuse but don't see a lot of consensus on the subject. – Ronald Wildenberg Apr 28 '10 at 06:06
  • @rwwilden: HttpModule is the only place to call `new MyEntities()`. DI does the rest. There is no way I would have to create context in UI. – LukLed Apr 28 '10 at 07:24
  • @LukLed But isn't the HttpModule part of the UI layer then? – Ronald Wildenberg Apr 28 '10 at 15:08
  • @rwwilden: I would say it is part of controller layer, but it doesn't really matter. It is instantiated once, can be really easily replaced with other code and there is actually no dependency. Context is passed to repository layer not by calling `HttpContext.Current.Items[@"MyEntities"]`, but with dependency injection rule. – LukLed Apr 28 '10 at 15:19
  • @rwwilden: I think that we both agree that storing context too long can be dangerous. Using per session or singleton can cause really serious problems. If you use it per operation and it works fine, ok. You can just have problems with objects in different contexts, that is also why I find using one context in request suitable. But still, the most important thing is not to keep it too long. – LukLed Apr 28 '10 at 15:26
  • @LukLed Agreed, keeping an ObjectContext alive too long is a bad idea. – Ronald Wildenberg Apr 28 '10 at 16:31
  • I actually don't understand why keeping a context during an http request is a bad idea: the point of having a cache inside the context seems to be right, you can use the cached objects during the entire life of the request. Is that really a bad idea? – Salvatore Previti Apr 24 '12 at 14:51
  • 1
    @SalvatorePreviti: Keeping context during http request is completely fine, but you shouldn't use it longer than request, because you can finish using outdated data. – LukLed Apr 24 '12 at 15:54
14

Definitely for every query. It's a lightweight object so there's not much cost incurred creating one each time you need it.

Besides, the longer you keep an ObjectContext alive, the more cached objects it will contain as you run queries against it. This may cause memory problems. Therefore, having the ObjectContext as a singleton is a particularly bad idea. As your application is being used you load more and more entities in the singleton ObjectContext until finally you have the entire database in memory (unless you detach entities when you no longer need them).

And then there's a maintainability issue. One day you try to track down a bug but can't figure out where the data was loaded that caused it.

Ronald Wildenberg
  • 31,634
  • 14
  • 90
  • 133
  • 3
    I'd agree with this answer if the only choices were singleton and on-access. But there is a whole spectrum of lifetimes, some of which might give better performance depending on the application. The context caches for a reason :) Per-request is the "safest" of the bunch next to on-access. – Merlyn Morgan-Graham Sep 13 '11 at 09:16
1

Don't use a singleton.. everyone using your app will share that and all sorts of crazy things will happen when that object context is tracking entities.

I would add it as a private member

Raj Kaimal
  • 8,304
  • 27
  • 18
1

Like Luke says this question has been asked numerous times on SO.

For a web application, per request cycle seems to work best. Singleton is definitely a bad idea.

Per request works well because one web page has a User, maybe some Projects belonging to that user, maybe some Messages for that user. You want the same ObjectContext so you can go User.Messages to get them, maybe mark some messages as read, maybe add a Project and then either commit or abandon the whole object graph at the completion of the page cycle.

Ian Mercer
  • 38,490
  • 8
  • 97
  • 133
0

Late post here by 7 months. I am currently tackling this question in my app and I'm leaning towards the @LukLed solution by creating a singleton ObjectContext for the duration of my HttpRequest. For my architecture, I have several controls that go into building a page and these controls all have their own data concerns that pull read-only data from the EF layer. It seems wasteful for them to each create and use their own ObjectContext's. Besides, there are a few situations where one control may pull data into the Context that could be reused by other controls. For instance, in my masterpage, my header at the top of the page has user information that can be reused by the other controls on the page.

My only worry is that I may pull entities into the context that will affect the queries of other controls. I haven't seen that yet but don't know if I'm asking for trouble. I guess we'll see!

sisdog
  • 2,649
  • 2
  • 29
  • 49
0
public class DBModel {

        private const string _PREFIX = "ObjectContext";

        // DBModel.GetInstance<EntityObject>();
        public static ObjectContext GetInstance<T>() {
            var key = CreateKey<T>();
            HttpContext.Current.Items[key] = HttpContext.Current.Items[key] ?? Activator.CreateInstance<T>();
            return HttpContext.Current.Items[key] as ObjectContext;
        }

        private static string CreateKey<T>() {
            return string.Format("{0}_{1}", _PREFIX, typeof(T).Name);
        }
    }
thkala
  • 84,049
  • 23
  • 157
  • 201
Ebubekir Dirican
  • 386
  • 4
  • 12