Sindre
Sindre

Reputation: 3930

Entity Framework and calling context.dispose()

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;
    }
    

Upvotes: 81

Views: 121011

Answers (6)

Daniel
Daniel

Reputation: 9521

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.

Upvotes: 43

Gotham Llianen
Gotham Llianen

Reputation: 604

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;
            }
        }
    }

Upvotes: 2

dimaaan
dimaaan

Reputation: 917

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);

Upvotes: 0

Gert Arnold
Gert Arnold

Reputation: 109080

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.

Upvotes: 123

A-Sharabiani
A-Sharabiani

Reputation: 19329

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;
    }
}

Upvotes: 3

Todd Menier
Todd Menier

Reputation: 39289

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.

Upvotes: 17

Related Questions