前言:上篇介紹了下倉儲的代碼架構示例以及簡單分析了倉儲了使用優點。本章仍是繼續來完善下倉儲的設計。上章說了,倉儲的最主要做用的分離領域層和具體的技術架構,使得領域層更加專一領域邏輯。那麼涉及到具體的實現的時候咱們應該怎麼作呢,本章就來講說倉儲裏面具體細節方便的知識。html
DDD領域驅動設計初探系列文章:sql
//倉儲的泛型實現類 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(); } }
倉儲接口:數據庫
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類型。架構
在菜單的倉儲接口裏面: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)模式。