82

When should one call DbContext.dispose() with entity framework?

  1. Is this imaginary method bad?

    public static string GetName(string userId)
    {
        var context = new DomainDbContext();
        var userName = context.UserNameItems.FirstOrDefault(x => x.UserId == userId);
        context.Dispose();
        return userName;
    }
    
  2. Is this better?

    public static string GetName(string userId)
    {
        string userName;
        using(var context = new DomainDbContext()) {
            userName = context.UserNameItems.FirstOrDefault(x => x.UserId == userId);
            context.Dispose();
        }
        return userName;
    }
    
  3. Is this even better, that is, should one NOT call context.Dispose() when using using()?

    public static string GetName(string userId)
    {
        string userName;
        using(var context = new DomainDbContext()) {
            userName = context.UserNameItems.FirstOrDefault(x => x.UserId == userId);
        }
        return userName;
    }
    
5
  • 27
    should one NOT call context.Dispose() when using using() is always true. It is redundant. Commented Mar 27, 2013 at 18:40
  • Thank you for your comment. So context.Dispose() is only redundant, removing it will not have any effect? Commented Mar 27, 2013 at 18:43
  • 4
    using is an implicit Dispose() Commented Mar 27, 2013 at 18:44
  • and DbContext is made to be short-living - so do whatever is one 'batch' of work - and get done with it Commented Mar 27, 2013 at 19:11
  • There is a bug in your code :-) - UserNameItems is surely a complex type collection and not a System.String collection, otherwise you wouldn't call x.UserId. I think you are missing a .Select(x=>x.UserId) call after Where, or there is an implicit cast operator to String. Commented Feb 7, 2015 at 11:02

6 Answers 6

123

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 a) Never when dependency injection is operational. The dependency container takes care of object life cycles.

1 b) When not using dependency injection, of using a context factory (for example, in Blazor applications), still never 1. You'd typically use a using block, which 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 because EF closes the database connection after each interaction with the database.

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. Unless, again, a DI container takes care of object life cycles.

Sign up to request clarification or add additional context in comments.

9 Comments

Hmmm, does "Never" still apply if you're not utilizing the "using" statement to wrap your context (referring to case 1)?
I didnt exactly get try-finally comment, do you mean try-catch? because I added into my catch part in case exception occurs. can you confirm if it is ok to dispose when exception is caught? thanks.
@batmaci No, I mean use a using construct, in stead of try-finally, because it's more or less the same. By a using you never have to call Dispose.
The answer to Never call dispose on your context is wrong - It depends on the type of application - ie. In MVC you override the dispose method of the controller and call dispose on the context - You only don't need to manually call it when using using
I still don't get it. If there's an exception thrown INSIDE the using. It automatically gets out of it but what happen to the connection ? Will an exception inside the using still dispose the connection immediately without having to dispose in the catch ?
|
43

New answer below. The previous one is currently outdated.

Important updates : It looks like that the current recommendation is to dispose the DbContext (I agree) BUT if you create it via dependency injection, Asp.net Core does it for you when the request ends.

So, if you do that

public class MyController
{
    private readonly ApplicationDbContext _context;

    public MyController(ApplicationDbContext context)
    {
        _context = context;
    }
}

Asp.net Core disposes the DbContext for you. More information here.

The final result is an ApplicationDbContext instance created for each request and passed to the controller to perform a unit-of-work before being disposed when the request ends.

4 Comments

I want to point out that this comment is from 2014. I'm writing this comment in 2020 and this answer might be completely wrong for newer EF versions or EF Core. Following the IDispose pattern should not be optional as not doing so may introduce all kinds of problems. The linked post only considers the database connection, but the Dispose method does a lot more than closing the connection.
Is it desirable to destroy the DbContext after all?
"A million of flies can't be wrong" doesn't work here. learn.microsoft.com/en-us/ef/core/dbcontext-configuration "It is important to dispose the DbContext after use. This ensures any: Unmanaged resources are freed. Events or other hooks are unregistered. Unregistering prevents memory leaks when the instance remains referenced."
17

Better still:

public static string GetName(string userId)
{
    using (var context = new DomainDbContext()) {
        return context.UserNameItems.FirstOrDefault(x => x.UserId == userId);
    }
}

No need to return the result from outside the using scope; just return it immediately and you'll still get the desired disposal behavior.

Comments

3

You can define your database context as a class field, and implement IDisposable. Something like below:

public class MyCoolDBManager : IDisposable
{
    // Define the context here.
    private DomainDbContext _db;

    // Constructor.
    public MyCoolDBManager()
    {
        // Create a new instance of the context.
        _db = new DomainDbContext();
    }

    // Your method.
    public string GetName(string userId)
    {           
        string userName = _db.UserNameItems.FirstOrDefault(x => x.UserId == userId);

        return userName;
    } 

    // Implement dispose method.
    // NOTE: It is better to follow the Dispose pattern.
    public void Dispose()
    {
         _db.dispose();
         _db = null;
    }
}

2 Comments

You might wanna take a look at the dispose pattern
To follow this guideline a Dispose method should be idempotent, such that it is callable multiple times without throwing an exception, you should either NOT set _bd to null or only dispose the _db when it's not null.
2

One might want to dispose of the context in some cases.

On the simplistic terms of the OP example, the using keyword is enough.

So when do we need to use dispose?

Look at this scenario: you need to process a big file or communication or web-service-contract that will generate hundreds or thousands of BD records.

Adding (+400) thousands or hundreds of entities in EF is a pain for performance: Entity framework performance issue, saveChanges is very slow

The solution is described very well on this site: https://entityframework.net/improve-ef-add-performance

TL;DR - I implemented this and so I ended up with something like this:

    /// <summary>
    /// Convert some object contract to DB records
    /// </summary>
    /// <param name="objs"></param>
    public void SaveMyList(WCF.MyContract[] objs)
    {
        if (objs != null && objs.Any())
        {
            try
            {
                var context = new DomainDbContext();
                try
                {
                    int count = 0;
                    foreach (var obj in objs)
                    {
                        count++;

                        // Create\Populate your object here....
                        UserNameItems myEntity = new UserNameItems();

                        ///bla bla bla

                        context.UserNameItems.Add(myEntity);

                        // https://entityframework.net/improve-ef-add-performance
                        if (count % 400 == 0)
                        {
                            context.SaveChanges();
                            context.Dispose();
                            System.Threading.Thread.Sleep(0); // let the system breathe, other processes might be waiting, this one is a big one, so dont use up 1 core for too long like a scumbag :D
                            context = new DomainDbContext();
                        }
                    }

                    context.SaveChanges();
                }
                finally
                {
                    context.Dispose();
                    context = null;
                }

                Log.Info("End");
            }
            catch (Exception ex)
            {
                Log.Error(string.Format("{0}-{1}", "Ups! something went wrong :( ", ex.InnerException != null ? ex.InnerException.ToString() : ex.Message), ex);
                throw ex;
            }
        }
    }

1 Comment

A better pattern is to process objs in chunks of 400, each chunk having one context in a using statement and one SaveChanges() call. Much cleaner code (no count, no if, etc.). And no compelling need to call context.Dispose.
0

As Daniel mentioned, you don't have to dispose the dbContext.

From the article:

Even though it does implement IDisposable, it only implements it so you can call Dispose as a safeguard in some special cases. By default DbContext automatically manages the connection for you.

So:

public static string GetName(string userId) =>
    new DomainDbContext().UserNameItems.FirstOrDefault(x => x.UserId == userId);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.