ورود

View Full Version : سوال: Dispose در Generic Repository Pattern



nunegandom
دوشنبه 13 آذر 1396, 10:43 صبح
با سلام
یک ریپوزیتوری جنریک و اینترفیس جنریک دارم
قسمت دیسپوز رو چجوری باید استفاده کنم که درست کار کنه؟
###Interface###
void Dispose();

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


protected virtual void Dispose(bool disposing)
{
if (disposing)
{
_context.Dispose();
}
}
پیاده سازیش درسته؟
چجوری پیاده سازیش کنم توی کلاس های کنترلر؟
توی destructor که نباید بذارم درسته؟ :متفکر:

Moien Tajik
دوشنبه 13 آذر 1396, 13:46 عصر
Repository نیازی به Dispose نداره چون ارتباطی با Database برقرار نمیکنه ، اگر داخل Repository ارتباطی با دیتابیس برقرار میکنید ، Pattern رو اشتباه پیاده سازی کردید.
ارتباط با دیتابیس در Unit Of Work برقرار میشه ، پس اونجا باید Dispose رو انجام بدید :


public interface IUnitOfWork : IDisposable
{
void Save();
}


public class UnitOfWork : IUnitOfWork
{
private DbContext _dbContext;


public UnitOfWork(DbContext context)
{
_dbContext = context;
}


public void Save()
{
_dbContext.SaveChanges();
}


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


private void Dispose(bool disposing)
{
if (disposing)
{
if (_dbContext != null)
{
_dbContext.Dispose();
_dbContext = null;
}
}
}
}

nunegandom
دوشنبه 13 آذر 1396, 14:48 عصر
با تشکر
من به این صورت پیاده سازی کردم:
RepositoryClass:
public class Repository<T> : IRepository<T> where T : class {
protected OriginContext _context;
public Repository(OriginContext context)
{
_context = context;
}
public T Get(int id)
{
return _context.Set<T>().Find(id);
}
public async Task<T> GetAsync(int id)
{
return await _context.Set<T>().FindAsync(id);
}
public ICollection<T> GetAll()
{
return _context.Set<T>().ToList();
}
public async Task<ICollection<T>> GetAllAsync()
{
return await _context.Set<T>().ToListAsync();
}
public T Find(Expression<Func<T, bool>> match)
{
return _context.Set<T>().SingleOrDefault(match);
}
public async Task<T> FindAsync(Expression<Func<T, bool>> match)
{
return await _context.Set<T>().SingleOrDefaultAsync(match);
}
public ICollection<T> FindAll(Expression<Func<T, bool>> match)
{
return _context.Set<T>().Where(match).ToList();
}
{
return await _context.Set<T>().Where(match).ToListAsync();
}
public T Add(T t)
{
_context.Set<T>().Add(t);
_context.SaveChanges();
return t;
}
public async Task<T> AddAsync(T t)
{
_context.Set<T>().Add(t);
await _context.SaveChangesAsync();
return t;
}
public IEnumerable<T> AddAll(IEnumerable<T> tList)
{
_context.Set<T>().AddRange(tList);
_context.SaveChanges();
return tList;
}
public async Task<IEnumerable<T>> AddAllAsync(IEnumerable<T> tList)
{
_context.Set<T>().AddRange(tList);
await _context.SaveChangesAsync();
return tList;
}
public T Update(T updated, int key)
{
if (updated == null)
return null;


T existing = _context.Set<T>().Find(key);
if (existing != null)
{
_context.Entry(existing).CurrentValues.SetValues(u pdated);
_context.SaveChanges();
}
return existing;
}
public async Task<T> UpdateAsync(T updated, int key)
{
if (updated == null)
return null;


T existing = await _context.Set<T>().FindAsync(key);
if (existing != null)
{
_context.Entry(existing).CurrentValues.SetValues(u pdated);
await _context.SaveChangesAsync();
}
return existing;
}
public void Delete(T t)
{
_context.Set<T>().Remove(t);
_context.SaveChanges();
}
public async Task<int> DeleteAsync(T t)
{
_context.Set<T>().Remove(t);
return await _context.SaveChangesAsync();
}
public int Count()
{
return _context.Set<T>().Count();
}
public async Task<int> CountAsync()
{
return await _context.Set<T>().CountAsync();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}


protected virtual void Dispose(bool disposing)
{
if (disposing)
{
_context.Dispose();
}
}
IRepositoryClass:
public interface IRepository<T> where T : class {
T Get(int id);
Task<T> GetAsync(int id);
ICollection<T> GetAll();
Task<ICollection<T>> GetAllAsync();
T Find(Expression<Func<T, bool>> match);
Task<T> FindAsync(Expression<Func<T, bool>> match);
ICollection<T> FindAll(Expression<Func<T, bool>> match);
Task<ICollection<T>> FindAllAsync(Expression<Func<T, bool>> match);
T Add(T t);
Task<T> AddAsync(T t);
IEnumerable<T> AddAll(IEnumerable<T> tList);
Task<IEnumerable<T>> AddAllAsync(IEnumerable<T> tList);
T Update(T updated, int key);
Task<T> UpdateAsync(T updated, int key);
Task<int> DeleteAsync(T t);
void Delete(T t);
int Count();
Task<int> CountAsync();
void Dispose();
}
الان این فقط قسمت Dispose ها اشتباه هست یا به کل؟
مثالی که به صورت جنریک پیاده سازی شده باشه سراغ دارید؟ که Generic Repository Pattern & Ninject & UnitTest رو پیاده سازی کرده باشه؟

Moien Tajik
دوشنبه 13 آذر 1396, 16:26 عصر
چند مورد کاملا اشتباه توی کدهاتون دیده میشه.
فلسفه ی Repository در ابتدا برای Decoupling هست و بعد کوتاه کردن کد.
داخل Repository نباید دستور SaveChanges در هیچ کدوم از متد ها استفاده بشه تا Transaction با دیتابیس برقرار بشه.
کار ذخیره تغییرات رو باید به Unit Of Work محول کنید.
اگر قرار باشه SaveChanges داخل Repository باشه ، به ازای هر SaveChanges باید یک Repository داشته باشید که این درست نیست.


مثالی که به صورت جنریک پیاده سازی شده باشه سراغ دارید؟ که Generic Repository Pattern & Ninject & UnitTest رو پیاده سازی کرده باشه؟
الان خیر ، تا شب ارسال میکنم.

nunegandom
دوشنبه 13 آذر 1396, 16:43 عصر
متشکرم
الان این نمونه درسته؟ (https://www.codeproject.com/Articles/770156/Understanding-Repository-and-Unit-of-Work-Pattern)

Moien Tajik
دوشنبه 13 آذر 1396, 22:47 عصر
این یک مثال ساده از GenericRepository.
بنده از StructureMap بجای Ninject استفاده کردم چون باهاش راحتترم و Convention Over Configuration هست ; برای Ninject هم زیاد تفاوت نمیکنه Register کردن Type هاتون.