Classe base:
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
}
Sottoclasse:
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
}
Classe logica:
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 ....
}
}
È questo il modo corretto di implementare IDisposable
su IDisposable
astratta della classe? Questo non sta seguendo i principali DRY come dovrebbe, ma non sono chiaro come farlo correttamente.
Voglio assicurarmi che sto pulendo il mio DbContext
appropriato.
EDIT: Sembra che siano necessarie maggiori informazioni per chiarire cosa sto facendo e perché sto passando in DbContext nel costruttore (ho aggiunto altro codice sopra per favore rileggere). Avevo bisogno del DbContext nella classe abstract per accedere al database e fare un po 'di lavoro. Non è questo il modo in cui utilizzerei una classe astratta condivisa tra più sottoclassi e quindi mi consente di aderire al principale di DRY e centralizzare la manutenzione futura?
Come potrei passare il DbContext alla classe abastract se non lo passo attraverso il contstructor (viene in mente l'iniezione del metodo ma ciò richiederebbe che gli sviluppatori dei futuri repository possano dimenticare di passare il contesto alla classe base).
se stai cercando una classe astratta usa e getta generica dai un'occhiata alla classe sottostante, ma come @Matthew e @D Stanley hanno detto ... il repository dovrebbe inizializzare il contesto ogni volta.
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);
}
}
per la tua implementazione del pattern di repository sarà così:
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);
}
}
così in voi Schedule Repository fa così
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
}
}
Modificare::::
la tua classe logica sembrerà così
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 ....
}
}
quindi non dipenderà da EF