[英]Generic Repository / Unit of Work Issue
我一直在学习各种来源的知识库和工作单元模式,包括:
如果您浏览上面的thr链接到创建工作单元类 ,则有以下内容:
private GenericRepository<Department> departmentRepository;
private GenericRepository<Course> courseRepository;
这很好,但我想继续扩展Generic的工作单元类并设置GenericRepositories的集合,这样我就可以根据我通过的模型进行动态更新。
我最终想在我的控制器中执行以下操作:
public class LedgerUserController : Controller
{
private GenericUnitOfWork unitOfWork = new GenericUnitOfWork();
LedgerUser ledgeruser = new LedgerUser();
public ActionResult Index()
{
//var ledgerusers = db.LedgerUsers.Include(l => l.Image).Include(l => l.UserType);
var view = unitOfWork.Repository(ledgeruser).Get(l => l.LastName == "smith");
return View(view.ToList());
}
}
所以这是我的类和接口到目前为止:
IRepository.cs
/// <summary>
/// Generic Repository for CRUD Operations and methods
/// to locate entities within your store. This is not specific to which Data Access
/// tools your are using (Direct SQL, EF, NHibernate, etc).
/// </summary>
public interface IRepository<T> where T : class
{
//--Search Operations
IQueryable<T> GetAll();
IEnumerable<T> GetAllList();
IEnumerable<T> Get(Expression<Func<T,bool>> filter);
T GetIt(Expression<Func<T, bool>> filter);
T GetById(object id);
//--CRUD Operations
void Create(T entity);
void Update(T entity);
void Delete(T entity);
}
GenericRepository.cs
/// ///用于查找实体的存储库类/// CRUD操作/// ///公共类GenericRepository:IRepository其中TEntity:class {
internal AccountsContext context;
internal DbSet<TEntity> dbSet;
internal IQueryable<TEntity> query;
/// <summary>
/// Default Constructor.
/// </summary>
/// <param name="context"></param>
public GenericRepository(AccountsContext context)
{
this.context = context;
this.dbSet = context.Set<TEntity>();
}
#region Methods
#region Search Functionality
/// <summary>
/// Obtain the whole Entity to query if needed.
/// </summary>
/// <returns>IQueryable object.</returns>
public virtual IQueryable<TEntity> GetAll()
{
IQueryable<TEntity> query = dbSet;
return query;
}
/// <summary>
/// Obtain the whole Entity to Enumerate throught if needed.
/// </summary>
/// <returns>IEnumerble object.</returns>
public virtual IEnumerable<TEntity> GetAllList()
{
IQueryable<TEntity> query = dbSet;
return query.ToList();
}
/// <summary>
/// Locate an Entity by its indexed id.
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public virtual TEntity GetById(object id)
{
return dbSet.Find(id);
}
/// <summary>
/// Gets a collection based on LINQ lambda expressions
/// </summary>
/// <param name="filter">Lambda Expression</param>
/// <returns>Query</returns>
public virtual IEnumerable<TEntity> Get(Expression<Func<TEntity, bool>> filter)
{
query = dbSet;
if (filter != null)
{
query = query.Where(filter);
}
return this.query.ToList();
}
/// <summary>
/// Gets one record based on a one-to-one relationship.
/// </summary>
/// <param name="filter">Lambda Expression.</param>
/// <returns>One record.</returns>
public virtual TEntity GetIt(Expression<Func<TEntity, bool>> filter)
{
IQueryable<TEntity> query = dbSet;
return query.SingleOrDefault(filter);
}
#endregion
#region CRUD Functionality
/// <summary>
/// Used to create a new entity into the database.
/// </summary>
/// <param name="entity">Entity to create.</param>
public virtual void Create(TEntity entity)
{
dbSet.Add(entity);
}
/// <summary>
/// Used to update an entity that already exists in the
/// database.
/// </summary>
/// <param name="entity">Entity to update.</param>
public virtual void Update(TEntity entity)
{
dbSet.Attach(entity);
context.Entry(entity).State = EntityState.Modified;
}
/// <summary>
/// Used to delete an entity from the database.
/// </summary>
/// <param name="entity">Entity to delete.</param>
public virtual void Delete(TEntity entity)
{
if (context.Entry(entity).State == EntityState.Detached)
{
dbSet.Attach(entity);
}
dbSet.Remove(entity);
}
#endregion
#endregion
}
#endregion
GenericUnitOfWork.cs :
/// <summary>
/// Unit of work class that handles multiple Repositories
/// and shares the context.
/// </summary>
public class GenericUnitOfWork : IUnitOfWork
{
private AccountsContext context = new AccountsContext();
Dictionary<string, GenericRepository<IRepository<IRepositoryEntity>>> repostories = null;
/// <summary>
/// Generic Repository method which checks the repository is available if not,
/// it sets it up.
/// </summary>
/// <param name="entity">Entity</param>
/// <returns>Repository to use.</returns>
public GenericRepository<IRepository<IRepositoryEntity>> Repository (IRepositoryEntity entity)
{
string index = entity.GetType().ToString();
if (!repostories.ContainsKey(index))
{
//Reflections to create the repoositiory if it is not needed.
Type type1 = typeof(GenericRepository<>);
Type[] typeArgs = {typeof(IRepositoryEntity)};
Type constructed = type1.MakeGenericType(typeArgs);
object o = Activator.CreateInstance(constructed);
if(o is GenericRepository<IRepository<IRepositoryEntity>>)
{
var rep = (GenericRepository<IRepository<IRepositoryEntity>>)o;
rep.context = this.context;
repostories.Add(index, rep);
}
}
return this.repostories[index];
}
/// <summary>
/// Save method.
/// </summary>
public void Save()
{
context.SaveChanges();
}
private bool disposed = false;
/// <summary>
/// Dispose the conxtext when finished.
/// </summary>
/// <param name="disposing"></param>
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
context.Dispose();
}
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
}
现在我知道存储库Dictionary的实现和方法库不正确(通用类型是错误的)因为在我的lambda表达式中它无法解析ledgeruser LastName。
var view = unitOfWork.Repository(ledgeruser).Get(l => l.LastName == "smith");
我是在设计这个问题,还是有一个很好的干净方式来创建我的通用存储库集合,这些通用存储库是基于模型对象给出的(例如上面的LedgerUser)设置和创建的。
一些想法:
您可以使用IoC容器并以这种方式自动创建存储库,而不是在UnitOfWork
实现中使用反射创建所有内容。 MVC框架实际上是为这种方法而构建的。 有关使用StructureMap的简单说明和示例,请访问http://www.mikesdotnetting.com/Article/117/Dependency-Injection-and-Inversion-of-Control-with-ASP.NET-MVC 。
如果您不想使用完整的IoC容器,您仍然可以针对接口标准化您的工厂逻辑和代码。 这起着同样的作用,但如果你想继续使用自定义的工作单元实现,可能会更好。 在我对C#/ EF和存储库模式的回答中:在哪里将ObjectContext放在具有多个存储库的解决方案中? ,我发布了一个RepositoryProvider
类,允许使用可定制的工厂创建UnitOfWork
-scoped存储库。 我建议至少查看此代码,因为它是一种类似但更有效的方法来执行代码示例的目标。 要理解的一件重要事情是,该答案中的示例使用ObjectContext作为UnitOfWork,因此您的更改需要通过将IUnitOfWork
的出现替换为ObjectContext
的出现来解决这种差异。 如果在查看代码后有任何关于该方法的内容尚不清楚,请告诉我,我将尝试解释如何调整您的特定用例。
看起来你的工厂逻辑有一些循环。 如果存储库创建了LedgerUser
,那么它不应该要求LedgerUser
来创建工厂。 在我看来,你真正想要的是一个Type
参数,比如unitOfWork.Repository(typeof(LedgerUser))
。 您可以通过在load上创建泛型类型参数来使其更流畅,并执行unitOfWork.Repository<LedgerUser
>()`。 根据您的示例,您似乎根本不需要实例。
在您的Repository
方法中,似乎您更喜欢强类型接口。 我想也许你想要的更像是:
public IRepository Repository()
where T : IRepositoryEntity
{
// your factory/cache-retrieval logic here
}
代替
public GenericRepository<IRepository<IRepositoryEntity>> Repository (IRepositoryEntity entity)
{
// your factory/cache-retrieval logic here
}
然后,如果您的调用是Repository<LedgerUser>
,则您的方法将返回GenericRepository<LedgerUser>
,即使签名显示IRepository<LedgerUser>
。 这几乎是我建议的RepositoryProvider
实现的链接。
我不明白为什么要将实例传递给对象而不是对象的类型,并按类型保存存储库:
试试这个
ConcurrentDictionary<Type, object> _repositories = ...;
public GenericRepository<IRepository<TEntity>> Repository<TEntity>(IRepositoryEntity entity) where TEntity: IRepositoryEntity
{
return (GenericRepository<IRepository<TEntity>>)_repositories.GetOrAdd(
typeof(TEntity),
t => new GenericRepository<IRepository<TEntity>>(this.Context)
);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.