Multi-Hierarchy IDisposable Implementation for DbContext in C#

c# entity-framework entity-framework-6

Question

Base class:

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
}

Sub Class:

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
}

Logic Class:

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

Is this the correct way to implement IDisposable on an abstract class implementation? This is not following the DRY principals like it should but I am unclear how to do this properly.

I want to make sure that I am cleaning up my DbContext appropriately.

EDIT: It appears that more information is needed to clarify what I am doing and why I am passing in DbContext in the constructor (I have added more code above to please re-read). I needed the DbContext in the abstract class to access the database and do some work. Isn't this how I would use an abstract class that is shared among multiple sub classes and thus allowing me to adhere to the DRY principal and centralize future maintenance?

How would I pass the DbContext to the abastract class if I dont pass it through the contstructor (method injection comes to mind but that would require that devs of future repositories might forget to pass the context to the base class).

1
0
4/10/2015 4:21:58 PM

Accepted Answer

if you are looking for generic disposable abstract class take a look at the below class , but as @Matthew and @D Stanley said ...the repository should initialize the context each time.

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

}

for your implementation of the repository pattern it will be like that:

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

so in you Schedule Repository do it like that

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

Edit::::

you logic class will look like that

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

so it won't depend on EF

0
4/10/2015 8:20:23 PM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow