Siemka
Pomijając to czy generic repo to zło czy nie to chciałbym się was zapytać o jakość takiej implementacji. Znalazłem taki przykład kiedyś i nawet kilka razy użyłem w kilku projektach (trochę rozbudowane CRUD-y). Niby działa i co całkiem sprawnie, ale jakie mogą być wpadki i ograniczenia takiej implementacji?
Jak widać obiekty są odłączane od kontekstu przy odczycie i podłączane przy zapisie i aktualizacji) ale po zmianach trzeba dostarczyć do obiektu info o EntityState (co nie jest jakimś problemem).
Dodatkowo umożliwia zapisanie czy aktualizację całego drzewa obiektów (o ile każdy obiekt na każdej gałęzi będzie miał określony EntityState).
Czyli czy Wam się podoba taki twór i dlaczego nie? :)
public interface IEntity
{
[NotMapped]
EntityState EntityState { get; set; }
}
public enum EntityState
{
Unchanged,
Added,
Modified,
Deleted
}
public class BaseEntity<T> : IEntity
{
public T Id { get; set; }
public DateTime Created { get; set; }
public BaseEntity()
{
Created = DateTime.UtcNow;
}
[NotMapped]
public EntityState EntityState { get; set; }
}
public interface IGenericDataRepository<T> : IDisposable where T : class, BetKom.Model.Common.IEntity
{
IList<T> GetAll(params Expression<Func<T, object>>[] navigationProperties);
IList<T> GetList(Func<T, bool> where, params Expression<Func<T, object>>[] navigationProperties);
T GetSingle(Func<T, bool> where, params Expression<Func<T, object>>[] navigationProperties);
void Add(params T[] items);
void Update(params T[] items);
void Remove(params T[] items);
}
public class GenericDataRepository<T> : IGenericDataRepository<T> where T : class, BetKom.Model.Common.IEntity
{
public GenericDataRepository()
{
}
public virtual IList<T> GetAll(params Expression<Func<T, object>>[] navigationProperties)
{
List<T> list;
using (var context = new DBContext())
{
IQueryable<T> dbQuery = context.Set<T>();
//Apply eager loading
foreach (Expression<Func<T, object>> navigationProperty in navigationProperties)
dbQuery = dbQuery.Include<T, object>(navigationProperty);
list = dbQuery
.AsNoTracking()
.ToList<T>();
}
return list;
}
public virtual IList<T> GetList(Func<T, bool> where,
params Expression<Func<T, object>>[] navigationProperties)
{
List<T> list;
using (var context = new DBContext())
{
IQueryable<T> dbQuery = context.Set<T>();
//Apply eager loading
foreach (Expression<Func<T, object>> navigationProperty in navigationProperties)
dbQuery = dbQuery.Include<T, object>(navigationProperty);
list = dbQuery
.AsNoTracking()
.Where(where)
.ToList<T>();
}
return list;
}
public virtual T GetSingle(Func<T, bool> where,
params Expression<Func<T, object>>[] navigationProperties)
{
T item = null;
using (var context = new DBContext())
{
IQueryable<T> dbQuery = context.Set<T>();
//Apply eager loading
foreach (Expression<Func<T, object>> navigationProperty in navigationProperties)
dbQuery = dbQuery.Include<T, object>(navigationProperty);
item = dbQuery
.AsNoTracking() //Don't track any changes for the selected item
.FirstOrDefault(where); //Apply where clause
}
if (item != null)
item.EntityState = BetKom.Model.Common.EntityState.Unchanged;
return item;
}
/* rest of code omitted */
public virtual void Add(params T[] items)
{
PUpdate(items);
}
public virtual void Update(params T[] items)
{
PUpdate(items);
}
public void PUpdate(params T[] items)
{
using (var context = new DBContext())
{
DbSet<T> dbSet = context.Set<T>();
foreach (T item in items)
{
dbSet.Attach(item);
var dd = context.ChangeTracker.Entries<IEntity>();
foreach (DbEntityEntry<IEntity> entry in dd)
{
IEntity entity = entry.Entity;
entry.State = GetEntityState(entity.EntityState);
}
}
context.SaveChanges();
}
public virtual void Remove(params T[] items)
{
PUpdate(items);
}
protected static System.Data.Entity.EntityState GetEntityState(BetKom.Model.Common.EntityState entityState)
{
switch (entityState)
{
case BetKom.Model.Common.EntityState.Unchanged:
return System.Data.Entity.EntityState.Unchanged;
case BetKom.Model.Common.EntityState.Added:
return System.Data.Entity.EntityState.Added;
case BetKom.Model.Common.EntityState.Modified:
return System.Data.Entity.EntityState.Modified;
case BetKom.Model.Common.EntityState.Deleted:
return System.Data.Entity.EntityState.Deleted;
default:
return System.Data.Entity.EntityState.Detached;
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
//// free managed resources
//if (managedResource != null)
//{
// managedResource.Dispose();
// managedResource = null;
//}
}
//// free native resources if there are any.
//if (nativeResource != IntPtr.Zero)
//{
// Marshal.FreeHGlobal(nativeResource);
// nativeResource = IntPtr.Zero;
//}
}
}