C# DbContext在C中的多层次IDisposable实现

C# DbContext在C中的多层次IDisposable实现,c#,entity-framework,entity-framework-6,C#,Entity Framework,Entity Framework 6,基类: public abstract class Repository : IDisposable { private bool _disposed; private DbContext _context; public Repository(DbContext context) { _context = context; } public void SetSomething() { //...Acces

基类:

public abstract class Repository : IDisposable
{
    private bool _disposed;
    private DbContext _context;
    public Repository(DbContext context)
    {
        _context = context;
    }

    public void SetSomething()
    {
        //...Access the database and set something for tracing
        _context.Database.SqlQuery(....);
    }

    public void UnSetSomething()
    {
        //...Access the database and cancel something for tracing
        _context.Database.SqlQuery(....);
    }

    #region Object Disposal
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    ~Repository()
    {
        Dispose(false);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (_disposed)
            return;

        if (disposing)
        {
            // free other managed objects that implement IDisposable only
            if (_context != null)
            {
                _context.Dispose();
                _context = null;
            }
        }

        _disposed = true;
    }
    #endregion
}
子类:

public class ScheduleRepository : Repository
{
    private AppContext _context;

    public ScheduleRepository(DbContext context)
        : base(context)
    {
        _context = (AppContext)context;
    }

    #region Object Disposal
    bool _disposed;
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    ~ScheduleRepository()
    {
        Dispose(false);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (_disposed)
            return;

        if (disposing)
        {
            // free other managed objects that implement IDisposable only
            if (_context != null)
            {
                _context.Dispose();
                _context = null;
            }
        }

        _disposed = true;

        base.Dispose(disposing);
    }
    #endregion
}
逻辑类:

public class ScheduleFacade
{
    private ScheduleRepository _repository;
    public ScheduleFacade()
    {
        _repository = new ScheduleRepository(AppContext.Create());
    }

    public ScheduleSetting GetScheduleById(string scheduleId)
    {
        if (!string.IsNullOrEmpty(scheduleId))
        {
            _repository.SetSomething();

            ScheduleSetting settings = _repository.GetScheduleById(scheduleId);

            _repository.UnSetSomething();

            return LoadScheduleSettings(settings);
        }
        else
        {
            throw new ArgumentException("The scheduleId parameter cannot be empty.");
        }
    }

    private ScheduleSetting LoadScheduleSettings(ScheduleSetting settings)
    {
        //...code ....
    }
}
这是在抽象类实现上实现IDisposable的正确方法吗?这并没有像它应该遵循的那样遵循干巴巴的原则,但我不清楚如何正确地做到这一点

我想确保我正在适当地清理DbContext

编辑:似乎需要更多的信息来澄清我在做什么,以及为什么要在构造函数中传递DbContext。我在上面添加了更多的代码,请重新阅读。我需要抽象类中的DbContext来访问数据库并执行一些工作。这不是我将如何使用一个在多个子类之间共享的抽象类,从而允许我遵循DRY原则并集中未来的维护吗


如果我不通过contstructor方法注入将DbContext传递给abastract类,我该如何传递给它呢?但这需要未来存储库的开发人员可能忘记将该上下文传递给基类。

如果您正在寻找通用的一次性抽象类,请查看下面的类,但是正如@Matthew和@dstanley所说的那样……存储库每次都应该初始化上下文

public abstract class DisposableObject : IDisposable
{
    private bool _disposed = false;

    public virtual bool IsDisposed
    {
        get { return _disposed; }
    }

    protected void CheckDisposed()
    {
        if (IsDisposed)
        {
            throw new ObjectDisposedException(this.GetType().FullName);
        }
    }

    protected void CheckDisposed(string err)
    {
        if (IsDisposed)
        {
            throw new ObjectDisposedException(this.GetType().FullName, err);
        }
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected void Dispose(bool disposing)
    {
        if (!_disposed)
        {
            OnDispose(disposing);
        }
        _disposed = true;
    }

    protected abstract void OnDispose(bool disposing); // this for the implementor to dispose their items

    ~DisposableObject()
    {
        Dispose(false);
    }

}
对于存储库模式的实现,如下所示:

public abstract class Repository<T> : IDisposable where T : DbContext
{
    private bool _disposed;
    private T _context;
    public Repository(T context)
    {
        _context = context;
    }

    protected T Context { get { return _context; } }

    public void SetSomething()
    {
        //...Access the database and set something for tracing
        // _context.Database.SqlQuery(....);
    }

    public void UnSetSomething()
    {
        //...Access the database and cancel something for tracing
        //_context.Database.SqlQuery(....);
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected void Dispose(bool disposing)
    {
        if (!_disposed)
        {
            if (_context != null)
            {
                _context.Dispose();
                _context = null;
            }

            OnDispose(disposing);
        }
        _disposed = true;
    }

    // this for the implementor to dispose their items but not the context because it's already disposed from the base class
    protected abstract void OnDispose(bool disposing); 

    ~Repository()
    {
        Dispose(false);
    }
}

所以它不依赖于EF

为什么不让上下文受到保护,而不是在基类中有一个不同的字段?这样就不需要重写任何基类dispose函数。事实上,如果您现在没有覆盖它们,那么您是在隐藏它们。我不会暗示您的存储库上的IDisposable,因为您处理上下文的唯一内容不是由存储库创建的,而是提供给它的。并不是所有类都符合这一点,但一个好的做法是让创建一次性的东西成为处理它的对象。为了补充Matthew的正确观点,存储库不应该包含对上下文的引用,而应该为每个请求创建上下文,“所以,没有必要让您的存储库成为一次性的。”Matthew我已经更新了我的问题。请重新阅读。首先尝试使用泛型,公共抽象类Repository:IDisposable,其中T:DbContextYou确定关于此实现的另一个问题。在代码中使用basenew AppContext,然后使用this.Context.Schedules。我没有看到一个私有变量/字段包含您在ctor中实例化的.Context。你能解释一下吗?在基本存储库中,我有一个接受T的ctor,其中T:DBContext,为了在驱动类ScheduleRepository中使用这个上下文,我刚刚在存储库中创建了一个受保护的属性,以便访问上下文“受保护的T上下文{get return{U context;}”'我的意思是在子类中使用this.Context.Schedules。我看到您在ctor中为基类创建了一个新的AppContext,但是如何在子类中使用这个新实例化的上下文呢?我是否也需要在子类中创建新上下文?this.context.Schedules。。。将使用u在新AppContext中实例化的,因为它将从基类继承。。。顺便说一下,Schedules是我写的一个名称,您可能在AppContext类中有另一个属性名称,它引用DBAh中的Schedule表。我忘了继承权。
public class ScheduleRepository : Repository<AppContext>
{

    public ScheduleRepository()
        :base(new AppContext())
    {

    }
    public Schedule GetById(int id) { 
        this.Context.Schedules. (....) // blah blah
    }

    protected override void OnDispose(bool disposing)
    {
        // if you are working with any thing that you must free it up
        // do it here, but not the context
    }
}
public class ScheduleFacade
{
    private ScheduleRepository _repository;
    public ScheduleFacade()
    {
        _repository = new ScheduleRepository();
    }

    public ScheduleSetting GetScheduleById(string scheduleId)
    {
        if (!string.IsNullOrEmpty(scheduleId))
        {
            _repository.SetSomething();

            ScheduleSetting settings = _repository.GetScheduleById(scheduleId);

            _repository.UnSetSomething();

            return LoadScheduleSettings(settings);
        }
        else
        {
            throw new ArgumentException("The scheduleId parameter cannot be empty.");
        }
    }

    private ScheduleSetting LoadScheduleSettings(ScheduleSetting settings)
    {
        //...code ....
    }
}