【问题标题】:Should I dispose DbContext when using Entity Framework Core使用 Entity Framework Core 时我应该处置 DbContext
【发布时间】:2019-09-05 17:38:14
【问题描述】:

我在aspx文件(.NET Framework 4.6.2项目)中有如下方法:

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

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

AveragePeriodDaysService 类有一个接受DbContext 实例的构造函数:

public class AveragePeriodDaysService
{
    private readonly MyDbContext _ctx;

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

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

这里是EfHelper 类:

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

问题。我应该处置 MyDbContext 吗?如果是,我应该怎么做?

【问题讨论】:

    标签: c# entity-framework-core dispose idisposable


    【解决方案1】:

    作为一条规则,你永远不应该释放你从外部获得的依赖,因为你永远不知道还有谁使用了这个依赖的同一个实例。这意味着AveragePeriodDaysService 无法处置MyDbContext。但是SetAvgPeriodDays 确切地知道谁将使用MyDbContext,因为它请求创建MyDbContext,因此它可以并且应该在使用后处理它。使用using关键字:

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

    【讨论】:

      【解决方案2】:

      我实际上不太确定正确的模式是什么,但我通常采用以下方法(类似于 .NET Stream 或 SafeHandle 类):

      您的AveragePeriodDaysService 似乎确实控制了上下文(它将其存储在private readonly 字段中)。所以实际上这个类应该实现IDisposable 并处理上下文本身。

      另一方面,您可能希望为不同的“服务”类使用一个上下文,而不总是创建一个新的。所以如果这些类总是处理上下文会很烦人。

      所以我的实现方式是这样的:

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

      然后您可以决定创建的实例是否应该负责处置上下文,或者创建者是否需要保持控制。

      当然,如果创建的实例要获得控制权,则需要妥善处置此实例。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-11-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-05-20
        • 2022-01-01
        • 1970-01-01
        • 2018-06-09
        相关资源
        最近更新 更多