代码之家  ›  专栏  ›  技术社区  ›  garfbradaz Vivek

通用存储库/工作单元问题

  •  5
  • garfbradaz Vivek  · 技术社区  · 13 年前

    我一直在学习 存储库 工作单位 来自各种来源的模式,包括以下内容:

    http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application

    如果您浏览到上面的链接 创建工作单元类 存在以下情况:

        private GenericRepository<Department> departmentRepository;
        private GenericRepository<Course> courseRepository;
    

    这很好,但我想尝试扩展Generic的工作单元类,并设置一个GenericRepository集合,这样我就可以根据我通过的模型动态更新。

    我最终想在我的 控制器 以下为:

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

    到目前为止,我的类和接口如下:

    I存储.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);
    
    }
    

    通用存储库.cs

    /// ///用于查找实体的存储库类 ///CRUD操作 /// /// 公共类GenericRepository: I存放处,其中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
    

    通用工作单位.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);
        }
    
    }
    

    }

    现在我知道Repositorys的实现Dictionary和Repository方法是不正确的(Generic Types是错误的),因为在我的lambda表达式中,它无法解析ledgeruser LastName。

    var view = unitOfWork.Repository(ledgeruser).Get(l => l.LastName == "smith");
    

    我是否过度设计了这个问题,或者是否有一种很好的干净的方法来使用我的通用存储库集合创建通用工作单元,这些存储库是基于模型对象给定(例如上面的LedgerUser)设置和创建的。

    2 回复  |  直到 13 年前
        1
  •  4
  •   Community Mohan Dere    9 年前

    一些想法:

    1. 而不是在你的 UnitOfWork 实现时,您可以使用IoC容器并以这种方式自动创建存储库。MVC框架实际上就是为这种方法而构建的。有关为此目的使用StructureMap的简单解释和示例,请访问 http://www.mikesdotnetting.com/Article/117/Dependency-Injection-and-Inversion-of-Control-with-ASP.NET-MVC

    2. 如果你不想使用一个成熟的IoC容器,你仍然可以根据接口标准化你的工厂逻辑和代码。这起到了同样的作用,但如果您想继续使用自定义的工作单元实现,可能会更好地工作。在我对 C#/EF and the Repository Pattern: Where to put the ObjectContext in a solution with multiple repositories? ,我发布了 RepositoryProvider 类,该类允许创建 工作单位 -具有可定制工厂的作用域存储库。我建议至少查看一下这段代码,因为这是一种类似但更有效的方法来实现代码示例的目标。需要理解的一件重要事情是,该答案中的示例使用ObjectContext作为UnitOfWork,因此您的更改需要通过替换 ObjectContext 发生 IUnitOfWork 。如果在查看代码后对该方法有任何不清楚的地方,请告诉我,我将尝试解释如何调整您的特定用例。

    3. 你的工厂逻辑似乎有些循环。如果存储库创建 LedgerUser s、 那么就不需要 分类帐用户 创建工厂。在我看来,你真正想要的似乎是 Type 类似参数 unitOfWork.Repository(typeof(LedgerUser)) 。您可以通过创建一个重载的泛型类型参数来使其更加流畅,并执行 unitOfWork.Repository<LedgerUser >()`。根据您的示例,似乎根本没有任何理由需要一个实例。

    4. 看起来你更喜欢强输入而不是你的 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> 存储库提供程序 我建议的实施方案行之有效。

        2
  •  2
  •   esskar    13 年前

    我不明白为什么要将实例而不是对象的类型传递给对象,并按类型保存存储库:

    试试这个

    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)
        );
    }
    
    推荐文章