概要:1、實現EF上線文線程唯一,有效避免了臟數據問題。
2、實現IBaseDao中定義的CRUD方法
一、創建數據訪問層程序集
1.1 在解決方案中創建Implements文件夾,以存放實現體部分的程序集
1.2 在Implements文件夾中創建Cnblogs.Rdst.Dao程序集
1.3 添加如下引用
二、創建ObjectContextFactory獲取EF上下文
2.1 在Cnblogs.Rdst.Dao程序集中創建ObjectContextFactory類,用來獲取EF上下文。
當數據庫更換為Mysql或其他數據庫時,在這個類中可以實現替換。
當網站訪問量增大時,為避免EF產生的臟數據問題,我們使用System.Runtime.Remoting.Messaging 命名空間下的CallContext來解決線程內上下文唯一。
CallContex更多了解http://msdn.microsoft.com/zh-cn/library/system.runtime.remoting.messaging.callcontext(v=VS.80).aspx
2.2 在ObjectContextFactory類中定義一個靜態方法,用於對EF上下文進行處理
1 using System; 2 using System.Collections.Generic; 3 using System.Data.Objects; 4 using System.Linq; 5 using System.Runtime.Remoting.Messaging; 6 using System.Text; 7 using Cnblogs.Rdst.Domain; 8 using Cnblogs.Rdst.IDAO; 9 10 namespace Cnblogs.Rdst.Dao 11 { 12 public class ObjectContextFactory 13 { 14 public static System.Data.Objects.ObjectContext GetCurrentObjectContext() 15 { 16 //從CallContext數據槽中獲取EF上下文 17 ObjectContext objectContext = CallContext.GetData(typeof (ObjectContextFactory).FullName) as ObjectContext; 18 if (objectContext==null) 19 { 20 //如果CallContext數據槽中沒有EF上下文,則創建EF上下文,並保存到CallContext數據槽中 21 objectContext = new ModelContainer();//當數據庫替換為MySql等,只要在次出EF更換上下文即可。 22 CallContext.SetData(typeof(ObjectContextFactory).FullName,objectContext); 23 } 24 return objectContext; 25 } 26 } 27 }
三、創建BaseDao,並實現CRUD方法
3.1 創建BaseDao類,實現IBaseDao中定義方法,用於所有實體類繼承此基類。
3.2 BaseDao類實現代碼
EF應用中需要注意:1、增加和查詢是不需要附加實體的,如果刪除和更新不是從上下文獲取的實體,就需要先附加,再進行狀態更改。
2、處理查詢,增刪改都需要調用SaveChange()提交操作。
1 using System; 2 using System.Collections.Generic; 3 using System.Data.Objects; 4 using System.Linq; 5 using System.Text; 6 using Cnblogs.Rdst.IDAO; 7 8 9 namespace Cnblogs.Rdst.Dao 10 { 11 public class BaseDao<T> 12 where T:class, 13 new() 14 15 { 16 ObjectContext objectContext= ObjectContextFactory.GetCurrentObjectContext() as ObjectContext;//獲取EF上下文 17 18 /// <summary> 19 /// 加載實體集合 20 /// </summary> 21 /// <param name="whereLambda"></param> 22 /// <returns></returns> 23 public virtual IQueryable<T> LoadEntites(Func<T,bool> whereLambda) 24 { 25 return objectContext.CreateObjectSet<T>().Where<T>(whereLambda).AsQueryable<T>(); 26 } 27 28 /// <summary> 29 /// 分頁加載數據 30 /// </summary> 31 /// <param name="whereLambda">過濾條件</param> 32 /// <param name="pageIndex">頁碼</param> 33 /// <param name="pageSize">頁大小</param> 34 /// <param name="totalCount">總記錄數</param> 35 /// <returns></returns> 36 public virtual IQueryable<T> LoadEntites(Func<T,bool> whereLambda, int pageIndex, int pageSize, out int totalCount) 37 { 38 var tmp= objectContext.CreateObjectSet<T>().Where<T>(whereLambda); 39 totalCount = tmp.Count(); 40 41 return tmp.Skip<T>(pageSize * (pageIndex - 1))//跳過行數,最終生成的sql語句是Top(n) 42 .Take<T>(pageSize) //返回指定數量的行 43 .AsQueryable<T>(); 44 } 45 46 /// <summary> 47 /// 添加實體 48 /// </summary> 49 /// <param name="entity"></param> 50 /// <returns>返回更新后的實體</returns> 51 public virtual T AddEntity(T entity) 52 { 53 objectContext.CreateObjectSet<T>().AddObject(entity); 54 objectContext.SaveChanges(); 55 return entity; 56 } 57 58 /// <summary> 59 /// 更新實體 60 /// </summary> 61 /// <param name="entity"></param> 62 /// <returns>返回更新后的實體</returns> 63 public virtual T UpdateEntity(T entity) 64 { 65 objectContext.CreateObjectSet<T>().Attach(entity); 66 objectContext.ObjectStateManager.ChangeObjectState(entity, System.Data.EntityState.Modified);//將附加的對象狀態更改為修改 67 objectContext.SaveChanges(); 68 return entity; 69 } 70 71 /// <summary> 72 /// 刪除實體 73 /// </summary> 74 /// <param name="entity"></param> 75 /// <returns></returns> 76 public virtual bool DelEntity(T entity) 77 { 78 objectContext.CreateObjectSet<T>().Attach(entity); 79 objectContext.ObjectStateManager.ChangeObjectState(entity, System.Data.EntityState.Deleted);//將附加的實體狀態更改為刪除 80 if (objectContext.SaveChanges()>0) 81 { 82 return true;//刪除成功 83 } 84 else 85 { 86 return false;//刪除失敗 87 } 88 } 89 90 /// <summary> 91 /// 根據條件刪除對象 92 /// </summary> 93 /// <param name="whereLambda">條件</param> 94 /// <returns></returns> 95 public virtual bool DelEntityByWhere(Func<T, bool> whereLambda) 96 { 97 var tmp= objectContext.CreateObjectSet<T>().Where<T>(whereLambda);//根據條件從數據庫中獲取對象集合 98 foreach (var entity in tmp) 99 { 100 objectContext.CreateObjectSet<T>().DeleteObject(entity);//標記對象為刪除狀態刪除 101 } 102 if (objectContext.SaveChanges() > 0) 103 { 104 return true; 105 } 106 else 107 { 108 return false; 109 } 110 } 111 } 112 }
四、使用T4模版生成所有實體對象的實現
4.1 和系列二中的方法一樣創建T4模版,生成所有的實體類繼承自BaseDao並實現各自的接口
以下是T4模版中的代碼,需要更改相應的EF edmx模型路徑、引用命名空間等。
<#@ 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.IDAO; using Cnblogs.Rdst.Domain; namespace Cnblogs.Rdst.Dao { <# foreach (EntityType entity in ItemCollection.GetItems<EntityType>().OrderBy(e => e.Name)) {#> public partial class <#=entity.Name#>Dao:BaseDao<<#=entity.Name#>>,I<#=entity.Name#>Dao { } <#};#> }
4.2 T4模版編輯完成后,ctrl+s保存並運行,就生成了所有實體類的實現了
至此也就實現了數據訪問層的增刪改查以及分頁查詢。
菜鳥級三層框架(EF+MVC)項目實戰之 系列二 對數據訪問層的抽象下 將實現數據訪問層對業務層的統一入口