简体   繁体   中英

Should I dispose DbContext when using Entity Framework Core

I have the following method in the aspx file (.NET Framework 4.6.2 project):

public static string SetAvgPeriodDays(int userId)
{
    var service = new AveragePeriodDaysService(EfHelper.GetContext());

    try
    {
        return service.SetAveragePeriodDays(userId);
    }
    catch (Exception e)
    {
        return e.Message;
    }
}

AveragePeriodDaysService class has a constructor that accepts DbContext instance:

public class AveragePeriodDaysService
{
    private readonly MyDbContext _ctx;

    public AveragePeriodDaysService(MyDbContext ctx)
    {
        _ctx = ctx;
    }

    public string SetAveragePeriodDays(int userId)
    {
        // main logic goes here...
    }
}

And here EfHelper class:

public class EfHelper
{   
    public static MyDbContext GetContext()
    {
        var options = new DbContextOptionsBuilder<MyDbContext>();

        var connectionString = ...
        options.UseSqlServer(connectionString);
        options.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);

        return new MyDbContext(options.Options);
    }
}

Question. Should I dispose MyDbContext? If yes, how should I do it properly?

As a rule you should never dispose dependencies that you got from outside because you never know who else uses same instance of this dependency. It means AveragePeriodDaysService can't dispose MyDbContext . But SetAvgPeriodDays knows exactly who will consume MyDbContext because it requested the creation of MyDbContext , hence it can and should dispose it after usage. Use using keyword:

public static string SetAvgPeriodDays(int userId)
{
    using(var ctx = EfHelper.GetContext())
    {
        var service = new AveragePeriodDaysService(ctx);

        try
        {
            return service.SetAveragePeriodDays(userId);
        }
        catch (Exception e)
        {
            return e.Message;
        }
    }
}

I'm actually not so sure what the correct patterns for this are, but I normally go with the following approach (something like the .NET Stream or SafeHandle classes do):

Your AveragePeriodDaysService really seems to take control of the context (it stores it in a private readonly field). So actually this class should implement IDisposable and dispose of the context itself.

On the other hand, you might want to use a single context for different "service" classes without always creating a new one. So it would be annoying if these classes always dispose the context.

So my way of implementing it would be something like this:

public class AveragePeriodDaysService : IDisposable
{
    private readonly MyDbContext _ctx;
    private readonly bool _ownContext;

    public AveragePeriodDaysService(MyDbContext ctx, bool ownContext)
    {
        _ctx = ctx;
        _ownContext = ownContext;
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposing) GC.SuppressFinalize(this);
        if (_ownContext) _ctx.Dispose();
    }

    public void Dispose()
    {
        Dispose(true);
    }

Then you can decide if the created instance should be responsible for disposing the context or if the creator needs to keep control.

Of course, if the created instance should take control, you need to properly dispose of this instance.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM