When Should I Dispose of a Data Context

When should I dispose of a data context

It actually doesn't matter too much. I asked Matt Warren from the LINQ to SQL team about this a while ago, and here's the reply:

There are a few reasons we implemented
IDisposable:

If application logic needs to hold
onto an entity beyond when the
DataContext is expected to be used or
valid you can enforce that contract by
calling Dispose. Deferred loaders in
that entity will still be referencing
the DataContext and will try to use it
if any code attempts to navigate the
deferred properties. These attempts
will fail. Dispose also forces the
DataContext to dump its cache of
materialized entities so that a single
cached entity will not accidentally
keep alive all entities materialized
through that DataContext, which would
otherwise cause what appears to be a
memory leak.

The logic that automatically closes
the DataContext connection can be
tricked into leaving the connection
open. The DataContext relies on the
application code enumerating all
results of a query since getting to
the end of a resultset triggers the
connection to close. If the
application uses IEnumerable's
MoveNext method instead of a foreach
statement in C# or VB, you can exit
the enumeration prematurely. If your
application experiences problems with
connections not closing and you
suspect the automatic closing behavior
is not working you can use the Dispose
pattern as a work around.

But basically you don't really need to dispose of them in most cases - and that's by design. I personally prefer to do so anyway, as it's easier to follow the rule of "dispose of everything which implements IDisposable" than to remember a load of exceptions to it - but you're unlikely to leak a resource if you do forget to dispose of it.

Am I using DataContext.Dispose() properly?

Well after some more digging I came across this post:

http://stephenwalther.com/blog/archive/2008/08/20/asp-net-mvc-tip-34-dispose-of-your-datacontext-or-don-t.aspx

and in the comments section Craig Stuntz wrote:

Failing to Dispose an object which implements IDisposable typically results in the object going into the finalization queue (read Chapter 19 of Jeffrey Richter's Applied Microsoft .NET Framework Programming for details). The results of this is that an object's memory that might have otherwise been freed in generation 01 be freed until a later generation collection. If you're creating a lot of these objects, well, do the math.

So you should always Dispose any object which implements IDisposable.

In the case of Controllers and DataContexts, this turns out to be really easy, because Controller also implements IDisposable, and hence has a virtual Dispose method you can override. So you don't have to wrap your use of DataContext in a using. You can create it in the constructor (or wherever) and then dispose in the overridden Controller.Dispose. In this case, using IQueryable in the view works just fine, because the framework does not Dispose the Controller until the View has been rendered.

So I did what Craig suggested and overrode the Dispose method that the Controller inherits.

At the top of my controller code:

    Repository repository;

// Default Contructor
public MyController()
{
repository = new Repository();
}

protected override void Dispose(bool disposing)
{
repository.Dispose();
}

and in my Repository I have a method called Dispose that looks like:

    public void Dispose()
{
db.Dispose();
}

where db is my DataContext.

Now my overriden Dispose method gets called every time :) and I don't have to wrap all my ActionResult in using blocks

Entity Framework and calling context.dispose()

In fact this is two questions in one:

  1. When should I Dispose() of a context?
  2. What should be the lifespan of my context?

Answers:

  1. Never 1. using is an implicit Dispose() in a try-finally block. A separate Dispose statement can be missed when an exception occurs earlier. Also, in most common cases, not calling Dispose at all (either implicitly or explicitly) isn't harmful.

  2. See e.g. Entity Framework 4 - lifespan/scope of context in a winform application. In short: lifespan should be "short", static context is bad.


1 As some people commented, an exception to this rule is when a context is part of a component that implements IDisposable itself and shares its life cycle. In that case you'd call context.Dispose() in the Dispose method of the component.

How do I correctly manage the disposing of a DataContext?

I managed to fix this myself...

I had a base class that had a method that would create the DataContext instance, like this:

public abstract class MyBase {

protected static DataContext db = null;

protected static DataContext GetDataContext() {
return new DataContext("My Connection String");
}

// rest of class
}

And then, in the classes that inherited MyBase where I wanted to do my queries, I had statements like this:

using (db = GetDataContext()) { ... }

The thing is, I wanted to access the database from both static methods and non-static methods, and so in my base class, I'd declared the db variable as static... Big mistake!

If the DataContext variable is declared as static, during heavy loads when lots of things are happening at the same time the DataContext is shared among the requests, and if something happens on the DataContext at exactly the same time it screws up the instance of the DataContext, and the Database connection stored in the Application pool for all subsequent requested until it's recycled, and the database connection is refreshed.

So, the simple fix is to change this:

protected static DataContext db = null;

to this:

protected DataContext db = null;

...which will break all of the using statements in the static methods. But this can easily be fixed by declaring the DataContext variable in the using instead, like this:

using (DataContext db = GetDataContext()) { ... }

Repository pattern where does data context dispose go?

If you are using a using statement, which you should be doing, the call is automatically disposed as it implements the IDisposable interface.

Such as:

public int GetThingCount()
{
using (MyDataContext context = new MyDataContext()) // context is created here
{
return context.Things.Count();
} // it is automatically disposed of here even in the event of an exception
}

http://msdn.microsoft.com/en-us/library/yh598w02.aspx

As a rule, when you use an IDisposable object, you should declare and
instantiate it in a using statement. The using statement calls the
Dispose method on the object in the correct way, and (when you use it
as shown earlier) it also causes the object itself to go out of scope
as soon as Dispose is called. Within the using block, the object is
read-only and cannot be modified or reassigned.

The using statement ensures that Dispose is called even if an
exception occurs while you are calling methods on the object. You can
achieve the same result by putting the object inside a try block and
then calling Dispose in a finally block; in fact, this is how the
using statement is translated by the compiler. The code example
earlier expands to the following code at compile time (note the extra
curly braces to create the limited scope for the object):

using NerdDinner as an example, when should the DataContext be disposed

Make the Repository itself disposable. Dispose the data context when the repository is disposed. Override Controller.Dispose and dispose the repository there. The controller is still alive when the view is executed.

How to dispose data context after usage

The example given by Codeka is correct, and I would advice writing your code with this when the method is called by the presentation layer. However, disposing DataContext classes is a bit tricky, so I like to add something about this.

The domain objects generated by LINQ to SQL (in your case the TB_Countries class) often contain a reference to the DataContext class. This internal reference is needed for lazy loading. When you access for instance list of referenced objects (say for instance: TB_Country.States) LINQ to SQL will query the database for you. This will also happen with lazy loaded columns.

When you dispose the DataContext, you prevent it from being used again. Therefore, when you return a set of objects as you've done in your example, it is impossible to call the States property on a TB_Country instance, because it will throw a ObjectDisposedException.

This does not mean that you shouldn't dispose the DataContext, because I believe you should. How you should solve this depends a bit on the architecture you choose, but IMO you basically got two options:

Option 1. Supply a DataContext to the GetCountriesQ method.
You normally want to do this when your method is an internal method in your business layer and it is part of a bigger (business) transaction. When you supply a DataContext from the outside, it is created outside of the scope of the method and it shouldn't dispose it. You can dispose it at a higher layer. In that situation your method basically looks like this:

public static IQueryable<TB_Country> GetCountriesQ(
Bn_Master_DataDataContext db)
{
return db.TB_Countries.OrderBy(o => o.CountryName);
}

Option 2. Don't return any domain objects from the GetCountriesQ method.
This solution is useful when the method is a public in your business layer and will be called by the presentation layer. You can wrap the data in a specially crafted object (a DTO) that contains only data and no hidden references to the DataContext. This way you have full control over the communication with the database and you can dispose the DataContext as you should. I've written more about his on SO here. In that situation your method basically looks like this:

public static CountryDTO[] GetCountriesQ()
{
using (var db = new Bn_Master_DataDataContext())
{
var countries;
from country in db.TB_Countries
orderby country.CountryName
select new CountryDTO()
{
Name = country.CountryName,
States = (
from state in country.States
order by state.Name
select state.Name).ToList();
};

return countries.ToArray();
}
}

public class CountryDTO
{
public string Name { get; set; }
public List<StateDTO> States { get; set; }
}

As you will read here there are some smart things you can do that make using DTOs less painful.

I hope this helps.

Is Disposing of Entity Framework context object required

Simply: DbContext implements IDisposable, therefore you should dispose of it, manually, as soon as you're done with it.

You don't need to dispose of it, because the GC will collect it eventually, but the GC isn't deterministic: you never know when "eventually" will be. Until it's disposed, it will be holding resources that aren't in use - for example, it may still have an open database connection. Those resources aren't freed until the GC runs, unless you dispose manually. Depending on specific details you may find that you have unnecessarily blocked network resources, file accesses, and you will certainly be keeping more memory reserved than you need to.

There's a further potential hit, too: when you dispose of an object manually, the GC doesn't typically need to call the Finalizer on that object (if there is one). If you leave the GC to automatically dispose of an object with a Finalizer, it'll place the object in a Finalizer Queue - and will automatically promote the object to the next GC generation. This means that an object with a finalizer will always hang around for orders of magnitude longer than it needs to before being GCed (as successive GC generations are collected less frequently). DBContext would likely fall into this category as the underlying database connection will be unmanaged code.

(Useful reference.)

Do WPF Windows Dispose() their DataContexts?

No!

WPF doesn't really use the IDisposable interface at all—and it can be a bit tricky to write WPF code that relies on it.

Consider using something like Caliburn Micro, an MVVM framework that supports matching views and view models (assigned to DataContext) and does support automatically calling Dispose(). Without knowing the specifics of your situation, though, CM may be a bit more than you need in your scenario.

If you're interested in why WPF doesn't use IDisposable, there are several posts on StackOverflow like this one that address this. Although this discusses why controls themselves aren't disposed, the rationale applies to the DataContext too, since it's just an inherited property of the control.



Related Topics



Leave a reply



Submit