C#中DbContext的多层次IDisposable实现

时间:2015-04-10 15:51:04

标签: 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()
    {
        //...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的正确方法吗?这不是像DRY校长那样遵循的,但我不清楚如何正确地做到这一点。

我想确保我正在清理DbContext

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

如果我没有通过contstructor传递它,我将如何将DbContext传递给abastract类(方法注入会浮现在脑海中,但这需要未来存储库的开发人员可能忘记将上下文传递给基类)。

1 个答案:

答案 0 :(得分:0)

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

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

所以你在Schedule Repository那样做

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

所以它不依赖于EF