77

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;
    }
    
TylerH
  • 20,799
  • 66
  • 75
  • 101
Sindre
  • 3,880
  • 2
  • 26
  • 39

6 Answers6

120

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.

TylerH
  • 20,799
  • 66
  • 75
  • 101
Gert Arnold
  • 105,341
  • 31
  • 202
  • 291
  • 4
    Hmmm, does "Never" still apply if you're not utilizing the "using" statement to wrap your context (referring to case 1)? – gitsitgo Sep 04 '13 at 19:28
  • 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. – Emil Jun 12 '14 at 17:02
  • @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`. – Gert Arnold Jun 12 '14 at 17:54
  • 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` – Luke T O'Brien Jan 09 '17 at 11:10
  • 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 ? – Marc Roussel Mar 18 '18 at 08:24
  • @MarcRoussel A context manages its own connections. They will be disposed properly. – Gert Arnold Mar 19 '18 at 08:57
  • @GertArnold immediately or not ? I ask because we ended up having SQL reporting that the connection pool has been reached and there's only one application using this SQL which is the one with using without any Context.Dispose inside the using and when we Dispose inside the using the connection pool is never reached and we clearly see that just one connection is used all the time – Marc Roussel Mar 20 '18 at 11:49
  • @MarcRoussel This is getting too complicated for comments. I suggest you ask a new question. – Gert Arnold Mar 20 '18 at 15:01
  • Another situation I would like to point out of when you should dispose and use a new context is when you have a SQL error in your current context. You can no longer use that context, it is essentially broken and unusable at that time. Any attempt to re-use that context will continue to fail for every subsequent call made. In this situation, you should dispose and get a new context in my opinion. Other than that this is the best answer with supporting link I have ever seen. Thank you. – dyslexicanaboko Apr 28 '20 at 18:10
42

I followed some good tutorials to use EF and they don't dispose the context.

I was a bit curious about that and I noticed that even the well respected Microsoft VIP don't dispose the context. I found that you don't have to dispose the dbContext in normal situation.

If you want more information, you can read this blog post that summarizes why.

James Skemp
  • 8,018
  • 9
  • 64
  • 107
Daniel
  • 9,312
  • 3
  • 48
  • 48
  • 5
    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. – Guillermo Prandi Sep 11 '20 at 22:34
  • Is it desirable to destroy the DbContext after all? – kisetu Sep 16 '21 at 01:30
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.

Todd Menier
  • 37,557
  • 17
  • 150
  • 173
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;
    }
}
Community
  • 1
  • 1
A-Sharabiani
  • 17,750
  • 17
  • 113
  • 128
  • 2
    You might wanna take a look at [the dispose pattern](https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/dispose-pattern#basic_pattern) – Jerry Joseph Sep 04 '18 at 15:25
  • 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. – R. Hoek Nov 03 '21 at 10:13
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;
            }
        }
    }
Gotham Llianen
  • 576
  • 1
  • 7
  • 19
  • 1
    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. – Gert Arnold Aug 11 '20 at 11:59
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);
dimaaan
  • 861
  • 13
  • 16