ASP.NET MVC+EF框架+EasyUI實現權限管系列 (開篇) (1):框架搭建 (2):數據庫訪問層的設計Demo (3):面向接口編程
前言:前面幾篇博客我們基本已經介紹完了搭建整個項目和數據庫訪問層以及一些業務邏輯層的實現,當然了,我們的數據庫訪問層這樣還是可以在進行封裝的,但是我到這里就行了吧,項目也不大,不需要那么麻煩的,那么我們今天開始介紹我們需要介紹的內容,那就是我們對業務邏輯的封裝,這個博客如果大家要看的話,我建議從第一張開始看是最容易理解的,廢話不多說了,我們直接切入主題。
1. 初步設計業務邏輯層
(1) 從昨天我們對LYZJ.UserLimitMVC.BLL類庫的操作,我們在這個類庫下面添加了UserInfoService,那么其他的實體對象也是有Service,那么這時候又是重復性的動作,UserInfo含有操作數據庫的所有方法,Role也含有操作數據庫的方法,其他的表一樣,那么我們怎么辦呢,當然就是封裝了,這時候我們就需要建立一個基類來實現這個動作。
(2) 首先我們在昨天的基礎上面添加兩個類,我們在LYZJ.UserLimitMVC.BLL類庫下面再添加一個RoleService類,BaseService類。
2.基類BaseService的分析
(1)首先BaseService類肯定是一個泛型,限制其繼承自類,這里面就會實現相應的增刪改查的方法。
(2)那么這時候我先將BaseService的一部分代碼帖上來,然后進行講解,想必如果開發過這類項目的人都知道這塊的使用,但是下面我還是解釋一下,解釋的不太好,完全是自己的語言,如果誰會解釋的更好,希望能夠給我留言,我將非常感謝。
1 namespace LYZJ.UserLimitMVC.BLL 2 { 3 public abstract class BaseService<T> where T : class, new() 4 { 5 public IDAL.IBaseRepository<T> CurrentRepository { get; set; } 6 //基類的構造函數 7 public BaseService() 8 { 9 SetCurrentRepository(); //構造函數里面去調用了,此設置當前倉儲的抽象方法 10 } 11 12 //約束 13 public abstract void SetCurrentRepository(); //子類必須實現 14 15 public T AddEntity(T entity) 16 { 17 //調用T對應的倉儲來做添加工作 18 return CurrentRepository.AddEntity(entity); 19 } 20 } 21 }
(3)下面就是我對上面代碼的分析
首先寫了方法Public T AddEntity(){return CurrentRepository.AddEntity(entity);},那么當我們對實體進行添加的時候,我們首先需要調用T對應的數據庫訪問層來調用相應的Entity方法,我們在昨天寫UserInfoService的時候,我們是直接調用了UserInfoRepository(倉儲)的Entity方法,但是現在我們在UserInfoService中的代碼都要放到基類中去實現,那么基類中的T對應的是那個數據庫訪問層的倉儲我們是不知道的,那么我們怎么辦呢?
不要慌,我們仔細分析代碼的話我們會發現解決之法,現在T對應的倉儲是誰呢?我們需要在方法里面調用來實現添加工作,現在首先假設我們知道我們T對應的倉儲叫CurrentRepository,我們只需要將entity參數傳遞給方法即可CurrentRepository.AddEntity(entity);,但是假設是假設,還是不成立的,但是這時候這就是我們的思想,我們已經知道這樣可以解決,所以我們只需要找到解決的辦法即可。
當前在我們基類中T對應的倉儲是誰我們不知道,這里可以使用反射來實現,但是我這里就不這么做了,既然我們基類不知道T對應的倉儲是誰?那么我們子類肯定T對應的倉儲是誰,因為子類對應的就是實體,所以這時候我們有辦法了,這時候我們只需要讓子類來設置這個屬性的實例不就完事了嗎,這時候我們在基類下面寫入一個屬性,注意:我們當前倉儲可能針對的是所有的表的倉儲,那么我們這樣寫:public abstract void SetCurrentRepository();,那麽下面我們調用接口的屬性就完事了。
這時候我們就想這里我們為什么要這么寫呢?因為當前倉儲可能指向任何一個倉儲,有可能指向UserInfo倉儲,也有可能指向RoleInfo倉儲等,那么這里我們使用IDAL.IBaseRepositroy完全可以,因為當你仔細看我花的那張圖的時候就看到了倉儲基本都間接地繼承自IBaseRepository倉儲,那麽我們使用IBase倉儲接收當前的倉儲是沒有任何問題的。
關鍵當我們這么定義的時候CurrentRepository是null,這時候我們下面方法如果調用的話可能會報出異常,那么在調用這個方法之前我們必須為CurrentRepository屬性賦值,那麽給這個屬性賦值在哪里比較合適呢,我想到了構造方法,構造方法給這個屬性賦值最合適,在這當前我們基類中也不知道CurrentRepository賦什么值,只有子類中才知道,這時候父類就想讓子類給這個屬性賦值,那麽怎么辦呢?我們定義一個抽象方法,當我們定義抽象方法的時候我們的類也要改成抽象的,抽象方法如下:public abstract void SetCurrentRepository(); ,這個抽象方法子類必須實現,在這里我在構造函數里面再去調用這個抽象方法。
在基類里面的構造函數調用父類的純的抽象方法,那麽經過多態的話最終調用方法的時候去執行子類里面的倉儲。
到這里我關於業務邏輯層的基類解釋已經完成了,個人感覺語言真心組織的不好,如果哪位看不懂或者怎么的,可以加群,我們在共同探討一下,到這里我們的LYZJ.UserLimitMVC.BLL類庫完成了
3. LYZJ.UserLimitMVC.BLL類庫的源代碼
(1)因為這個類庫的實現我已經在上面講玩了,所以這里不累贅的再說了,下面我直接貼最后的代碼,大家可以參考一下。
(2)BaseService.CS
1 namespace LYZJ.UserLimitMVC.BLL 2 3 { 4 5 public abstract class BaseService<T> where T : class, new() 6 7 { 8 9 public IDAL.IBaseRepository<T> CurrentRepository { get; set; } 10 11 //基類的構造函數 12 13 public BaseService() 14 15 { 16 17 SetCurrentRepository(); //構造函數里面去調用了,此設置當前倉儲的抽象方法 18 19 } 23 public abstract void SetCurrentRepository(); //子類必須實現 24 27 //實現對數據庫的添加功能 28 29 public T AddEntity(T entity) 30 31 { 32 33 //調用T對應的倉儲來做添加工作 34 35 return CurrentRepository.AddEntity(entity); 36 37 } 41 //實現對數據的修改功能 42 43 public bool UpdateEntity(T entity) 44 45 { 46 47 return CurrentRepository.UpdateEntity(entity); 48 49 } 53 //實現對數據庫的刪除功能 54 55 public bool DeleteEntity(T entity) 56 57 { 58 59 return CurrentRepository.DeleteEntity(entity); 60 61 } 65 //實現對數據庫的查詢 --簡單查詢 66 67 public IQueryable<T> LoadEntities(Func<T, bool> whereLambda) 68 69 { 70 71 return CurrentRepository.LoadEntities(whereLambda); 72 73 } 77 /// <summary> 78 79 /// 實現對數據的分頁查詢 80 81 /// </summary> 82 83 /// <typeparam name="S">按照某個類進行排序</typeparam> 84 85 /// <param name="pageIndex">當前第幾頁</param> 86 87 /// <param name="pageSize">一頁顯示多少條數據</param> 88 89 /// <param name="total">總條數</param> 90 91 /// <param name="whereLambda">取得排序的條件</param> 92 93 /// <param name="isAsc">如何排序,根據倒敘還是升序</param> 94 95 /// <param name="orderByLambda">根據那個字段進行排序</param> 96 97 /// <returns></returns> 98 99 public IQueryable<T> LoadPageEntities<S>(int pageIndex, int pageSize, out int total, Func<T, bool> whereLambda, 100 101 bool isAsc, Func<T, S> orderByLambda) 102 103 { 104 105 return CurrentRepository.LoadPageEntities(pageIndex, pageSize, out total, whereLambda, isAsc, orderByLambda); 106 107 } 108 109 } 110 111 }
(3)UserInfoService.cs
1 namespace LYZJ.UserLimitMVC.BLL 2 3 { 4 5 /// <summary> 6 7 /// UserInfo業務邏輯 8 9 /// </summary> 10 11 public class UserInfoService:BaseService<UserInfo> 12 13 { 14 15 public override void SetCurrentRepository() 16 17 { 18 19 CurrentRepository = DAL.RepositoryFactory.UserInfoRepository; 20 21 } 22 23 //訪問DAL實現CRUD 24 25 //private DAL.UserInfoRepository _userInfoRepository = new UserInfoRepository(); 26 27 //依賴接口編程 28 29 //private IUserInfoRepository _userInfoRepository = new UserInfoRepository(); 30 31 //private IUserInfoRepository _userInfoRepository = RepositoryFactory.UserInfoRepository; 32 33 //public UserInfo AddUserInfo(UserInfo userInfo) 34 35 //{ 36 37 // return _userInfoRepository.AddEntity(userInfo); 38 39 //} 40 41 //public bool UpdateUserInfo(UserInfo userInfo) 42 43 //{ 44 45 // return _userInfoRepository.UpdateEntity(userInfo); 46 47 //} 48 49 } 50 51 }
(4)RoleService.cs
1 namespace LYZJ.UserLimitMVC.BLL 2 3 { 4 5 public class RoleService:BaseService<Role> 6 7 { 8 9 //重寫抽象方法,設置當前倉儲為Role倉儲 10 11 public override void SetCurrentRepository() 12 13 { 14 15 //設置當前倉儲為Role倉儲 16 17 CurrentRepository = DAL.RepositoryFactory.RoleRepository; 18 19 } 20 21 } 22 23 }
4.業務邏輯接口層
(1)那麽我們業務邏輯層需不要一個接口層呢?我覺得需要,為什么呢?因為我們涉及到層與層之間的調用了,UI層調用業務邏輯層,我們一定要依賴接口來編程。那麽下面我們來實現業務邏輯接口層,這個和數據訪問接口層的作用基本一致。
(2)首先我們添加一個類庫LYZJ.UserLimitMVC.IBLL,用來實現對於業務邏輯接口層的封裝,然后我們新建三個接口:IUserInfoService,IRoleService,IBaseService。我們需要給這個類庫添加Model層的引用。下面我們寫出這三個接口層的代碼,我這里就不解釋了,和前面的意思都差不多。
(3) IBaseService接口
1 namespace LYZJ.UserLimitMVC.IBLL 2 3 { 4 5 public interface IBaseService<T> where T:class ,new () 6 7 { 8 9 // 實現對數據庫的添加功能,添加實現EF框架的引用 10 11 T AddEntity(T entity); 12 13 //實現對數據庫的修改功能 14 15 bool UpdateEntity(T entity); 16 17 //實現對數據庫的刪除功能 18 19 bool DeleteEntity(T entity); 20 21 //實現對數據庫的查詢 --簡單查詢 22 23 IQueryable<T> LoadEntities(Func<T, bool> whereLambda); 24 25 /// <summary> 26 27 /// 實現對數據的分頁查詢 28 29 /// </summary> 30 31 /// <typeparam name="S">按照某個類進行排序</typeparam> 32 33 /// <param name="pageIndex">當前第幾頁</param> 34 35 /// <param name="pageSize">一頁顯示多少條數據</param> 36 37 /// <param name="total">總條數</param> 38 39 /// <param name="whereLambda">取得排序的條件</param> 40 41 /// <param name="isAsc">如何排序,根據倒敘還是升序</param> 42 43 /// <param name="orderByLambda">根據那個字段進行排序</param> 44 45 /// <returns></returns> 46 47 IQueryable<T> LoadPageEntities<S>(int pageIndex, int pageSize, out int total, Func<T, bool> whereLambda, 48 49 bool isAsc, Func<T, S> orderByLambda); 50 51 } 52 53 }
(4) IUserInfoService接口
1 namespace LYZJ.UserLimitMVC.IBLL 2 3 { 4 5 public interface IUserInfoService:IBaseService<UserInfo> 6 7 { 8 9 } 10 11 }
(5) IRoleService接口
1 namespace LYZJ.UserLimitMVC.IBLL 2 3 { 4 5 public interface IRoleService:IBaseService<Role> 6 7 { 8 9 } 10 11 }
5.對業務邏輯層的再次修改
(1)當我們實現完業務邏輯接口層的時候,我們就需要讓BLL去實現這個接口,我們給BLL的類庫添加IBLL的引用,然后讓UserInfoService,RoleService實現各自的繼承關系,我這里就只貼出RoleService的代碼,其他的都一樣。
1 namespace LYZJ.UserLimitMVC.BLL 2 3 { 4 5 public class RoleService:BaseService<Role>,IRoleService 6 7 { 8 9 //重寫抽象方法,設置當前倉儲為Role倉儲 10 11 public override void SetCurrentRepository() 12 13 { 14 15 //設置當前倉儲為Role倉儲 16 17 CurrentRepository = DAL.RepositoryFactory.RoleRepository; 18 19 } 20 21 } 22 23 }
6.小結
(1)到這里我們今天的業務邏輯層完成了,從今天開始,我們這個Demo的后台涉及已經全部完成,我們明天開始涉及其前台頁面。今天的這篇文章本人感覺寫的也不是很好,重點是語言太難組織,靈活性太大,所以需要看此博客的博友們我建議從第一篇博客看起,那麽就能很容易的理解這些講的是什么。
(2)整體框架層圖紙
(3)最終的Demo項目架構圖
源碼下載
(1):完整源碼下載
Kencery返回本系列開篇