前言:上篇介紹了下倉儲的程式碼架構示例以及簡單分析了倉儲了使用優勢。本章還是繼續來完善下倉儲的設計。上章說了,倉儲的最主要作用的分離領域層和具體的技術架構,使得領域層更加專注領域邏輯。那麼涉及到具體的實現的時候我們應該怎麼做呢,本章就來說說倉儲裡面具體細節方便的知識。
一、對倉儲介面以及實現基類的完善
1、倉儲實現基類的所有方法加上virtual關鍵字,方便具體的倉儲在特定需求的時候override基類的方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
//倉儲的泛型實現類 public class EFBaseRepository : IRepositorywhere TEntity : AggregateRoot { [Import(typeof(IEFUnitOfWork))] public IEFUnitOfWork UnitOfWork { get; set; } public EFBaseRepository() { Regisgter.regisgter().ComposeParts(this); } public virtual IQueryable Entities { get { return UnitOfWork.context.Set(); } } public virtual TEntity GetByKey(object key) { return UnitOfWork.context.Set().Find(key); } public virtual IQueryable Find(Expressionbool>> express) { Funcbool> lamada = express.Compile(); return UnitOfWork.context.Set().Where(lamada).AsQueryable(); } public virtual int Insert(TEntity entity) { UnitOfWork.RegisterNew(entity); return UnitOfWork.Commit(); } public virtual int Insert(IEnumerable entities) { foreach (var obj in entities) { UnitOfWork.RegisterNew(obj); } return UnitOfWork.Commit(); } public virtual int Delete(object id) { var obj = UnitOfWork.context.Set().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 entities) { foreach (var entity in entities) { UnitOfWork.RegisterDeleted(entity); } return UnitOfWork.Commit(); } public virtual int Delete(Expressionbool>> express) { Funcbool> lamada = express.Compile(); var lstEntity = UnitOfWork.context.Set().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(); } } |
2、查詢和刪除增加了傳參lamada表示式的方法
倉儲介面:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
public interface IRepositorywhere TEntity : AggregateRoot { //........... #region 公共方法 /// /// 根據lamada表示式查詢集合 /// /// lamada表示式 /// IQueryable Find(Expressionbool>> express); /// /// 根據lamada表示式刪除物件 /// /// lamada表示式 /// 操作影響的行數 int Delete(Expressionbool>> express); //.......... } |
倉儲的實現
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
//倉儲的泛型實現類 public class EFBaseRepository : IRepositorywhere TEntity : AggregateRoot { //............. public virtual IQueryable Find(Expressionbool>> express) { Funcbool> lamada = express.Compile(); return UnitOfWork.context.Set().Where(lamada).AsQueryable(); } public virtual int Delete(Expressionbool>> express) { Funcbool> lamada = express.Compile(); var lstEntity = UnitOfWork.context.Set().Where(lamada); foreach (var entity in lstEntity) { UnitOfWork.RegisterDeleted(entity); } return UnitOfWork.Commit(); } //............. } |
增加這兩個方法之後,對於單表的一般查詢都可以直接通過lamada表示式的方法傳入即可,並且返回值為IQueryable型別。
3、對於涉及到多張表需要連表的查詢機制,我們還是通過神奇的Linq來解決。例如我們有一個通過角色取角色對應的選單的介面需求。
在選單的倉儲介面裡面:
1 2 3 4 5 6 7 |
/// /// 選單這個聚合根的倉儲介面 /// public interface IMenuRepository:IRepository { IQueryable GetMenusByRole(TB_ROLE oRole); } |
對應倉儲實現:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
[Export(typeof(IMenuRepository))] public class MenuRepository:EFBaseRepository,IMenuRepository { public IQueryable GetMenusByRole(TB_ROLE oRole) { var queryrole = UnitOfWork.context.Set().AsQueryable(); var querymenu = UnitOfWork.context.Set().AsQueryable(); var querymenurole = UnitOfWork.context.Set().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測試下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
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()的時候才會有查詢等待。
在dax.net的系列文章中,提到了規約模式的概念,用於解決條件查詢的問題。博主感覺這個東西設計確實牛叉,但實用性不太強,一般中小型的專案也用不上。
DDD領域驅動設計初探系列文章: