对数据访问层的抽象中
概要: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测试数据/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)项目实战之 系列二 对数据访问层的抽象下 将实现数据访问层对业务层的统一入口
系列概述: 全系列会详细介绍抽象工厂三层的搭建,以及EF高级应用和 ASP.NET MVC3.0简单应用,应用到的技术有Ef、Lambda、Linq、Interface、T4等。
由于网上对涉及到的技术概念介绍很多,因此本项目中不再对基本概念加以叙述。
系列二概述: 该系列详细介绍了如何抽象出公用方法(CRUD),以及T4模版的应用。
一、创建Cnblogs.Rdst.IDAO程序集1.1 先在解决方案中创建一个Interface 文件夹,用于存放抽象出的接口
1.2 在Interface文件夹中添加名为Cnblogs.Rdst.IDAO的程序集
1.3 添加引用系列一中创建的Domain程序集和System.Data.Entity程序集
二、抽象数据访问层的基接口
2.1 在刚创建的Cnblogs.Rdst.IDAO程序集中创建IBaseDao接口
2.2 在IBaseDao中定义常用的CRUD方法
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5
6 namespace Cnblogs.Rdst.IDAO
7 {
8 public interface IBaseDao<T>
9 where T: class ,
10 new () // 约束T类型必须可以实例化
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 }
此时基接口中的CRUD方法就定义完成。接下来我们需要使用T4模版生成所有的实体类接口并实现IBaseDao接口。
三、生成所有的实体类接口
3.1 添加名为IDaoExt 的T4文本模版
3.2 在模版中贴入以下代码,其中注释的地方需要根据各自的项目进行更改
<#@ 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" ; //指定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; //引用Domain的命名空间
namespace Cnblogs.Rdst.IDAO //实体类接口所在的命名空间
{
<#
foreach (EntityType entity in ItemCollection.GetItems<EntityType>().OrderBy(e => e.Name)) //便利edmx模型中映射的实体对象
{#>
public interface I<#=entity.Name#>Dao:IBaseDao<<#=entity.Name#>> //生成实体对象接口
{
}
<#};#>
}
3.3 T4模版编辑完成后,Ctrl+s保存,提示是否运行,点击确认。此时就自动帮我们生成了所有的实体类接口,并实现了IBaseDao接口,相应的也具有了CRUD方法定义。
菜鸟级三层框架(EF+MVC)项目实战之 系列二 对数据访问层的抽象中 会介绍实现类中是如何实现基接口中定义的方法
标签: EF , Entity , 框架 , 接口 , 抽象工厂
作者: Leo_wl
出处: http://HdhCmsTestcnblogs测试数据/Leo_wl/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
版权信息