概要: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)项目实战之 系列二 对数据访问层的抽象下 将实现数据访问层对业务层的统一入口