DDD领域驱动设计初探(三):仓储Repository(下)

前言:上篇介绍了下仓储的代码架构示例以及简单分析了仓储了使用优点。本章仍是继续来完善下仓储的设计。上章说了,仓储的最主要做用的分离领域层和具体的技术架构,使得领域层更加专一领域逻辑。那么涉及到具体的实现的时候咱们应该怎么作呢,本章就来讲说仓储里面具体细节方便的知识。html

DDD领域驱动设计初探系列文章:sql

1、对仓储接口以及实现基类的完善

一、仓储实现基类的全部方法加上virtual关键字,方便具体的仓储在特定需求的时候override基类的方法。

复制代码
  //仓储的泛型实现类
    public class EFBaseRepository<TEntity> : IRepository<TEntity> where TEntity : AggregateRoot
    {
        [Import(typeof(IEFUnitOfWork))]
        public IEFUnitOfWork UnitOfWork { get; set; }

        public EFBaseRepository()
        {
            Regisgter.regisgter().ComposeParts(this);
        }

        public virtual IQueryable<TEntity> Entities
        {
            get { return UnitOfWork.context.Set<TEntity>(); }
        }

        public virtual TEntity GetByKey(object key)
        {
            return UnitOfWork.context.Set<TEntity>().Find(key);
        }

        public virtual IQueryable<TEntity> Find(Expression<Func<TEntity, bool>> express)
        {
            Func<TEntity, bool> lamada = express.Compile();
            return UnitOfWork.context.Set<TEntity>().Where(lamada).AsQueryable<TEntity>();
        }

        public virtual int Insert(TEntity entity)
        {
            UnitOfWork.RegisterNew(entity);
            return UnitOfWork.Commit();
        }

        public virtual int Insert(IEnumerable<TEntity> entities)
        {
            foreach (var obj in entities)
            {
                UnitOfWork.RegisterNew(obj);
            }
            return UnitOfWork.Commit();
        }

        public virtual int Delete(object id)
        {
            var obj = UnitOfWork.context.Set<TEntity>().Find(id);
            if (obj == null)
            {
                return 0;
            }
            UnitOfWork.RegisterDeleted(obj);
            return UnitOfWork.Commit();
        }

        public virtual int Delete(TEntity entity)
        {
            UnitOfWork.RegisterDeleted(entity);
            return UnitOfWork.Commit();
        }

        public virtual int Delete(IEnumerable<TEntity> entities)
        {
            foreach (var entity in entities)
            {
                UnitOfWork.RegisterDeleted(entity);
            }
            return UnitOfWork.Commit();
        }

        public virtual int Delete(Expression<Func<TEntity, bool>> express)
        {
            Func<TEntity, bool> lamada = express.Compile();
            var lstEntity = UnitOfWork.context.Set<TEntity>().Where(lamada);
            foreach (var entity in lstEntity)
            {
                UnitOfWork.RegisterDeleted(entity);
            }
            return UnitOfWork.Commit();
        }

        public virtual int Update(TEntity entity)
        {
            UnitOfWork.RegisterModified(entity);
            return UnitOfWork.Commit();
        }
    }
复制代码

 

二、查询和删除增长了传参lamada表达式的方法

仓储接口:数据库

复制代码
   public interface IRepository<TEntity> where TEntity : AggregateRoot
    {
        //...........

        #region 公共方法

        /// <summary>
        /// 根据lamada表达式查询集合
        /// </summary>
        /// <param name="selector">lamada表达式</param>
        /// <returns></returns>
        IQueryable<TEntity> Find(Expression<Func<TEntity, bool>> express);

            /// <summary>
        ///     根据lamada表达式删除对象
        /// </summary>
        /// <param name="selector"> lamada表达式 </param>
        /// <returns> 操做影响的行数 </returns>
        int Delete(Expression<Func<TEntity, bool>> express);

         //..........
  }
复制代码

仓储的实现express

复制代码
   //仓储的泛型实现类
    public class EFBaseRepository<TEntity> : IRepository<TEntity> where TEntity : AggregateRoot
    {
        //.............

        public virtual IQueryable<TEntity> Find(Expression<Func<TEntity, bool>> express)
        {
            Func<TEntity, bool> lamada = express.Compile();
            return UnitOfWork.context.Set<TEntity>().Where(lamada).AsQueryable<TEntity>();
        }

        public virtual int Delete(Expression<Func<TEntity, bool>> express)
        {
            Func<TEntity, bool> lamada = express.Compile();
            var lstEntity = UnitOfWork.context.Set<TEntity>().Where(lamada);
            foreach (var entity in lstEntity)
            {
                UnitOfWork.RegisterDeleted(entity);
            }
            return UnitOfWork.Commit();
        }

    //.............
    }
复制代码

增长这两个方法以后,对于单表的通常查询均可以直接经过lamada表示式的方法传入便可,而且返回值为IQueryable类型。架构

 

三、对于涉及到多张表须要连表的查询机制,咱们仍是经过神奇的Linq来解决。例如咱们有一个经过角色取角色对应的菜单的接口需求。

在菜单的仓储接口里面:app

复制代码
   /// <summary>
    /// 菜单这个聚合根的仓储接口
    /// </summary>
    public interface IMenuRepository:IRepository<TB_MENU>
    {
        IQueryable<TB_MENU> GetMenusByRole(TB_ROLE oRole);
    }
复制代码

对应仓储实现:ide

复制代码
  [Export(typeof(IMenuRepository))]
    public class MenuRepository:EFBaseRepository<TB_MENU>,IMenuRepository
    {
        public IQueryable<TB_MENU> GetMenusByRole(TB_ROLE oRole)
        {
            var queryrole = UnitOfWork.context.Set<TB_ROLE>().AsQueryable();
            var querymenu = UnitOfWork.context.Set<TB_MENU>().AsQueryable();
            var querymenurole = UnitOfWork.context.Set<TB_MENUROLE>().AsQueryable();
            var lstres = from menu in querymenu
                         from menurole in querymenurole
                         from role in queryrole
                         where menu.MENU_ID == menurole.MENU_ID &&
                               menurole.ROLE_ID == role.ROLE_ID &&
                               role.ROLE_ID == oRole.ROLE_ID
                         select menu;
            return lstres;
        }
    }
复制代码

 这里也是返回的IQueryable接口的集合,千万不要小看IQueryable接口,它是一种表达式树,能够延迟查询。也就是说,在咱们执行GetMenusByRole()以后,获得的是一个带有查询sql语句的表达式树结构,并无去数据库执行查询,只有在咱们ToList()的时候才会去查询数据库。咱们来写个Demo测试下。post

复制代码
   class Program
    {
        [Import]
        public IUserRepository userRepository { get; set; }

        [Import]
        public IMenuRepository menuRepository { get; set; }

        static void Main(string[] args)
        {
            //注册MEF
            var oProgram = new Program();
            Regisgter.regisgter().ComposeParts(oProgram);
var lstFindUsers = oProgram.userRepository.Find(x => x.USER_NAME !=null);
            var lstRes = lstFindUsers.ToList();
            var lstMenu = oProgram.menuRepository.GetMenusByRole(new TB_ROLE() { ROLE_ID = "aaaa" });
            var lstMenuRes = lstMenu.ToList();
        }
    }
复制代码

来看执行过程:测试

 当程序执行var lstMenu = oProgram.menuRepository.GetMenusByRole(new TB_ROLE() { ROLE_ID = "aaaa" })这一步的时候基本是不耗时的,由于这一步仅仅是在构造表达式树,只有在.ToList()的时候才会有查询等待。更多详细能够看看此文 Repository 返回 IQueryable?仍是 IEnumerable?this

在dax.net的系列文章中,提到了规约模式的概念,用于解决条件查询的问题。博主感受这个东西设计确实牛叉,但实用性不太强,通常中小型的项目也用不上。有兴趣能够看看规约(Specification)模式

相关文章
相关标签/搜索