概述:業務邏輯層封裝相對數據訪問層來說較為簡單,我們分為以下幾步:
1、抽象基接口定義CRUD方法
2、應用T4模版生成所有實體接口
3、接口實現
一、接口定義
1.1、創建名為Cnblogs.Rdst.IBLL的程序集,主要用於業務邏輯層接口定義
並引用Cnblogs.Rdst.Domain和System.Data.Entity。這里需要注意,只要是用到EF實體,就需要添加System.Data.Entity引用。
1.2、創建IBaseService接口定義CRUD方法
這里可以直接將IBaseDao中定義的方法拷貝過來。
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 6 namespace Cnblogs.Rdst.IBLL 7 { 8 public interface IBaseService<T> 9 where T:class, 10 new () 11 { 12 //根據條件獲取實體對象集合 13 IQueryable<T> LoadEntites(Func<T, bool> whereLambda); 14 15 //根據條件獲取實體對象集合分頁 16 IQueryable<T> LoadEntites(Func<T, bool> whereLambda, int pageIndex, int pageSize, out int totalCount); 17 18 //增加 19 T AddEntity(T entity); 20 21 //更新 22 T UpdateEntity(T entity); 23 24 //刪除 25 bool DelEntity(T entity); 26 27 //根據條件刪除 28 bool DelEntityByWhere(Func<T, bool> whereLambda); 29 } 30 }
1.3、創建名為IServiceExt的T4模版,用於自動生成所有實體對象的接口,並繼承自IBaseService接口
以下是T4模版中的代碼:
<#@ template language="C#" debug="false" hostspecific="true"#> <#@ include file="EF.Utility.CS.ttinclude"#><#@ output extension=".cs"#> <# CodeGenerationTools code = new CodeGenerationTools(this); MetadataLoader loader = new MetadataLoader(this); CodeRegion region = new CodeRegion(this, 1); MetadataTools ef = new MetadataTools(this); string inputFile = @"..\\Cnblogs.Rdst.Domain\\Model.edmx"; EdmItemCollection ItemCollection = loader.CreateEdmItemCollection(inputFile); string namespaceName = code.VsNamespaceSuggestion(); EntityFrameworkTemplateFileManager fileManager = EntityFrameworkTemplateFileManager.Create(this); #> using System; using System.Collections.Generic; using System.Linq; using System.Text; using Cnblogs.Rdst.Domain; namespace Cnblogs.Rdst.IBLL { <# foreach (EntityType entity in ItemCollection.GetItems<EntityType>().OrderBy(e => e.Name)) {#> public interface I<#=entity.Name#>Service : IBaseService<<#=entity.Name#>> { } <#};#> }
以下是T4模版運行后,自動為我們生成的代碼:
至此,業務邏輯層的接口就定義完成了。
二、抽象出業務邏輯層的基類
2.1、創建名為Cnblogs.Rdst.BLL程序集,並添加DAO、Domain、IBLL、IDAO、System.Data.Entity程序集引用,如下圖
2.2、接下來是我們的重點,創建名為BaseService基類。該基類中實現了對數據訪問層的調用,也實現了CRUD
步驟: 1、先將IDBSessionFactory封裝為屬性,用於獲取IDBSession
2、再將IDBSession封裝為屬性,用於獲取EF上下文對象
3、定義IBaseDao類型的CurrentDao屬性,用於屬性獲取具體的實體對象
4、定義抽象方法 SetCurrentDao(),用於子類設置實現,為CurrentDao屬性賦具體的實體對象
以下是這部分代碼實現:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using Cnblogs.Rdst.IDAO; 6 using Cnblogs.Rdst.Dao; 7 8 9 namespace Cnblogs.Rdst.BLL 10 { 11 public abstract class BaseService<T> 12 where T : class, 13 new() 14 { 15 //構造函數 16 public BaseService() 17 { 18 //調用SetCurrentDao()方法,要求子類必須實現 19 SetCurrentDao(); 20 } 21 22 //獲取EF實體工廠 23 IDBSessionFactory _dbSessionFactory; 24 IDBSession _dbSession; 25 26 public IDBSessionFactory DbSessionFactory 27 { 28 get 29 { 30 if (_dbSessionFactory == null) 31 { 32 _dbSessionFactory = new DBSessionFactory(); 33 } 34 return _dbSessionFactory; 35 } 36 set { _dbSessionFactory = value; } 37 } 38 39 40 public IDBSession DbSession 41 { 42 get 43 { 44 if (_dbSession == null) 45 { 46 _dbSession = DbSessionFactory.GetCurrentDBSession();//通過數據訪問層提供的工廠獲取EF實體對象 47 } 48 return _dbSession; 49 } 50 set { _dbSession = value; } 51 } 52 //數據訪問層基接口類型可以接收數據訪問層的所有實體Dao 53 public IBaseDao<T> CurrentDao { get; set; } 54 55 //該方法用於子類實現,其作用是設置相應的實體Dao 56 public abstract void SetCurrentDao();
//以下是CRUD實現
2.3、實現CRUD
有了EF上下文,我們就可以實現CRUD
在實現增加和更新方法是,我們這時調用DBSessin中封裝的SaveChanges()方法進行提交,主要目的是實現業務層控制提交。
由於EF具有延遲加載特性,因此我們利用此特性,實現批量操作時,一次提交數據庫,已提程序高性能。
因此我們這時需要將BaseDao中的增加和更新方法中的SaveChange()方法注視掉,在此我就不貼出此部分代碼了。
以下是CRUD實現代碼:
1 //以下是CRUD實現 2 3 public virtual IQueryable<T> LoadEntites(Func<T, bool> whereLambda) 4 { 5 return this.CurrentDao.LoadEntites(whereLambda); 6 } 7 8 9 public virtual IQueryable<T> LoadEntites(Func<T, bool> whereLambda, int pageIndex, int pageSize, out int totalCount) 10 { 11 return this.CurrentDao.LoadEntites(whereLambda, pageIndex, pageSize, out totalCount); 12 } 13 14 15 public virtual T AddEntity(T entity) 16 { 17 var tmp= this.CurrentDao.AddEntity(entity); 18 this.DbSession.SaveChange(); 19 return tmp; 20 } 21 22 23 public virtual T UpdateEntity(T entity) 24 { 25 var tmp= this.CurrentDao.UpdateEntity(entity); 26 this.DbSession.SaveChange(); 27 return tmp; 28 } 29 30 31 public virtual bool DelEntity(T entity) 32 { 33 return this.CurrentDao.DelEntity(entity); 34 } 35 36 37 public virtual bool DelEntityByWhere(Func<T, bool> whereLambda) 38 { 39 return this.DelEntityByWhere(whereLambda); 40 } 41 } 42 }
至此,BaseService業務邏輯層基類就封裝完成,接下來使用T4模版自動生成所有實體。
2.4、創建名為ServiceExt的T4模版
以下是模版中的代碼:
<#@ template language="C#" debug="false" hostspecific="true"#> <#@ include file="EF.Utility.CS.ttinclude"#><#@ output extension=".cs"#> <# CodeGenerationTools code = new CodeGenerationTools(this); MetadataLoader loader = new MetadataLoader(this); CodeRegion region = new CodeRegion(this, 1); MetadataTools ef = new MetadataTools(this); string inputFile = @"..\\Cnblogs.Rdst.Domain\\Model.edmx"; EdmItemCollection ItemCollection = loader.CreateEdmItemCollection(inputFile); string namespaceName = code.VsNamespaceSuggestion(); EntityFrameworkTemplateFileManager fileManager = EntityFrameworkTemplateFileManager.Create(this); #> using System; using System.Collections.Generic; using System.Linq; using System.Text; using Cnblogs.Rdst.IBLL; using Cnblogs.Rdst.Domain; namespace Cnblogs.Rdst.BLL { <# foreach (EntityType entity in ItemCollection.GetItems<EntityType>().OrderBy(e => e.Name)) {#> public partial class <#=entity.Name#>Service : BaseService<<#=entity.Name#>>, I<#=entity.Name#>Service { public override void SetCurrentDao() { this.CurrentDao = this.DbSession.<#=entity.Name#>Dao; } } <#};#> }
以下是運行T4模版后自動生成的代碼:
這時我們就對業務邏輯層封裝完成,系列四中使用MVC3.0簡單實現增刪改查以及分頁功能。