1

Situation: What I'd like to do is have access to the data context for the life cycle of a page. This is primarily to (a) avoid series of using() and to avoid (b) out of scope exceptions in the view when a lazy loaded property is accessed.

Edit: I'm using MVC 4 and Entity Framework 4.3.1 (the latest)

What I typically do is

using (MyDB b = new MyDB()) {
 ...do all my stuff
}

In my controller or the data layer. The nice thing about this, based on my reading, is it's clean, causes no memory leaks etc. But the disadvantage is that even for the lifecycle of a single page I end up doing this again and again, and my objects lose context in the view as I've already disposed of the context.

I did some reading and found a similar post from 2009 but with no code in the answer. Surely some others have figured out how to solve this - I figure I have to do something with

Application_BeginRequest and EndRequest

But I'm just not sure how, and what the gotchas/best practices are.

Thank you for your help (with some code sample if possible!)

jeremy
  • 1,595
  • 2
  • 13
  • 15

4 Answers4

2

I see you have a tag for asp.net MVC so I assume that is what you're using.

You should be implementing a repository approach like http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application

Anyways, all you really need to do is something like this on each of your controllers

private MyDB b = null;
public MyController()
{
      b = new MyDB();
}

protected override void Dispose(bool disposing)
{
      b.Dispose();
      base.Dispose(disposing);
}
David Esteves
  • 1,614
  • 2
  • 15
  • 22
  • Thanks - did a quick read of the repository approach which I think maybe an overkill for my application (at least at this point). But your solution for a page level access to the context seems simple and elegant! I will try it and come back. – jeremy Apr 21 '12 at 17:40
  • I added a BaseController which I inherit from in some of my smaller pages, and added this code. Does what I need! – jeremy Apr 21 '12 at 17:50
  • I used suggested repository and unit of work before, but after time i dropped it as it was too much and not enough generic. So i suggest that you try and make you're own solution. – Matija Grcic Apr 21 '12 at 18:05
  • Repository Pattern All The Things!! Not. – Mike Cole Nov 08 '13 at 21:28
1

The way you wish to use your datacontext is absolutely a no-no (unless you are handling a couple of hundred lines database, in which case why EF at all).

But if you have a real production sized database, pinning the context to application scope will result in the following:

  • Since you are mentioning to use lazyload ( a feature I would totally switch of on the server side) sooner or later all you database will be slurped into memory (the context level entity cache)
  • your entity instances will be shared among requests and threads (yes, for write operations true)
  • EntitySet/DbSet is all but threadsafe
  • your write operations will be totally slow and unpredictable as you'll wont be able to save "just your changes" you'll save everything that changed since the last save/submitChanges, and you'll probably save someone other threads half baked entities too

The EF context is IDisposable with a very good reason: it is expected to be used in compact, short operations, and yes: you are supposed to do the using(...) "thing" all the time.

All the above is only a concern if you are building a website, intranet soluton, etc that will be used by more then one person.

Peter Aron Zentai
  • 11,482
  • 5
  • 41
  • 71
  • Peter - if I'm interpreting right, you're saying that my current approach is the good one (i.e. I use using() and keep the context for very short periods). I understand the disadvantages by keeping scope at an application level (e.g. as a Singleton) - but I'm not suggesting that. Why would it be very bad to keep context for the life of a single page request and dispose at the end of it? – jeremy Apr 21 '12 at 17:17
1

First don't use lazy loading (Entity Framework goes to the database and brings the results back one row at a time) in the views as queries from the views are bad practice and result in Select N+1 (Select N + 1 is a data access anti-pattern where the database is accessed in a suboptimal way.) or similar bad practices.

Using more than one object context means using more than one database connection per request, resulting in additional strain on the database and slower overall performance also each object context is not aware of the entities that are tracked by the other object context and might have to query the database again for its current state or have to issue an unnecessary update

When writing views, you shouldn't be bothered with thinking about persistence, or the number of queries that you views are generating.

Summary:

  1. Perform all your queries in the action.

  2. Force an eager load of the collection using the Include method to specify what pieces of the object model you want to include in the initial query.

  3. Use one object context per request.

Regards

Matija Grcic
  • 12,963
  • 6
  • 62
  • 90
  • Very useful commentary, thanks. I have begun to do an include() in the action to load what I need, and I'm limiting my contexts to either 1 per page request or much shorter with the using () depending on the need. – jeremy Apr 21 '12 at 20:32
0

you can return before you exit the using block so the context will be in scope when lazy loading in the view

using (MyDB b = new MyDB()) {
 ...do all my stuff

  return View(b.Data);
}
Clive
  • 1,128
  • 2
  • 11
  • 19
  • It is just not true. The fact that the return keyword is before the closing braces does not mean that the context it's not disposed by the time clients can access the resulted View... – Peter Aron Zentai Apr 22 '12 at 12:32
  • This doesn't work. I'm sure I tried this - the context does get disposed before I can access properties in my view. – jeremy Apr 25 '12 at 05:55