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)模式

相關文章
相關標籤/搜索