find a location for property in a new city

Friday, 4 March 2011

Why you shouldn't use singleton DataContexts in Entity Framework

I have been struggling recently with putting an end to a problem caused my optimistically keeping the same DataContext alive in a singleton pattern. Let me tell you what I found and why I think it is bad.

Getting it wrong will cripple your site

The first and foremost reason why you shouldn't use it is that if you set it up wrong the repercussions are critical. Here's my horror story: after ages of head scratching, wondering why the CPUs are continuously nearing 100% and memory leaks are ubiquitous I finally figured out that DataContexts were not being disposed of. Of course this is by design - lovely singleton pattern...

Anyway, not only were they not being disposed of they were being instantiated with every access of the data. So we ended up with piles of open connections, which I assume were being terminated randomly by some critical process. This causes huge memory utilisation and huge CPU usage trying to reallocate memory.

Fine so it was implemented incorrectly, but it is practically impossible to see that this is happening during development without shelling out for a decent entity framework profiler (like Entity Profiler - it is very much worth it if you don't trust EF).

Data isn't in sync sometimes...

When we were using the singleton well the data often seemed out of sync with the database. It's as if the ObjectContext knew best and didn't really care what the database had to say. This is not wise when you are working on a web farm since your different servers will have a different view of what the data is in its memory.

The way to resolve this is to begin a new connection... In comes the problem of multiplying open and undisposed connections.

Where's the performance gain anyway?

Has anyone any idea of how expensive it is to open a DataContext connection? Answer: "A DataContext is lightweight and is not expensive to create" [citation]. So why is everyone so intent on saving the hassle of creating a DataContext?

You are probably saving a few 10s of milliseconds. The word micro optimisation springs to mind - in which case you probably shouldn't be using Entity Framework.

It allows poor coding

Having a DataContext that is never closed allows you to lazy load whenever you want. You may have left your Service and now be in your Controller or worse still, your View. Accessing the database from a View is asking for performance problems as I'm sure you didn't allow that intentionally. It is most likely because you forgot to eager load all the data you need to populate your view.

This also makes it hard to keep things nice and streamlined since you don't know where all your queries are coming from.

Conclusion

If you are a guru of Entity Framework and you think a Singleton DataContext is for you then by all means go for it. If you aren't convinced you need it and you're just experimenting you could encounter unexpected and serious problems. Don't use singleton because you think it sounds cool!

Also, during fixing up my problems I found the Entity Profiler invaluable. It tracks how many connections have been opened and closed (hopefully they will be equal). It also shows all the actual SQL that is being produced, the results, the query plan and even tips on how to sort your query out. Invaluable!

Follow britishdev on Twitter

3 comments:

  1. How did you fix the Singleton Problem?

    Steve

    ReplyDelete
  2. Though pretty late to comment now, this might be useful for someone who land here.

    The dataContext/objectContext should be short lived and should be disposed. Advised way to be used is to use Unit_Of_Work pattern, where this context will be created for a unit of work and will be disposed once the unit of work is over.

    If you are using a clumsy code and do not follow Unit_Of_Work patten, you may opt for using one data context for one function of for one form/page.

    Creating contexts many times is not going to be an issue, especially in par with one big long lived context.

    ReplyDelete
  3. Just always put the Datacontext inside a USING statement as all the documentation suggests...

    ReplyDelete