菜鸟级三层框架(EF+MVC)项目实战之 系列二 对数据访问层的抽象下
概述:1、对数据访问层进行封装
2、对业务层提供统一入口
3、线程内实例唯一
一、数据访问层封装抽象
1.1、在程序集Cnblogs.Rdst.IDAO中创建IDBSession接口,其主要目的是将所有实体类封装为属性。
1.2、IDBSession接口中定义SaveChange()方法,定义该方法的意义会在业务逻辑中介绍。
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 partial interface IDBSession 9 { 10 int SaveChange();//用于在业务逻辑层对提交进行管理 11 } 12 }
1.3、创建名为IDBSessionExt的T4模版,实现自动生成IDBSession的部分接口,其中将所有实体类定义为接口属性,以实现对数据访问层的封装。
<#@ 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.IDAO { public partial interface IDBSession { <#foreach (EntityType entity in ItemCollection.GetItems<EntityType>().OrderBy(e => e.Name)) {#> I<#=entity.Name#>Dao <#=entity.Name#>Dao { get; set; } <#};#> } }
1.4、T4模版编辑完成后,运行后生成的代码如下:
二、数据访问层统一入口抽象
在程序集Cnblogs.Rdst.IDAO中创建IDbSessionFactory接口,为业务逻辑层提供统一访问入口。
该接口中定义GetCurrentDBSession()方法,其作用是通过该接口方法获取需要的实体对象。
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 IDBSessionFactory 9 { 10 IDBSession GetCurrentDBSession(); 11 } 12 }
三、实现IDBSession
3.1、在Cnblogs.Rdst.Dao程序集中创建DBSession 部分类
3.2、在Cnblogs.Rdst.Dao程序集中创建名为DBSessionExt的T4模版,将所有实体类自动封装为属性,以下是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.IDAO; namespace Cnblogs.Rdst.Dao { public partial class DBSession : IDBSession { <#foreach (EntityType entity in ItemCollection.GetItems<EntityType>().OrderBy(e => e.Name)) {#> private I<#=entity.Name#>Dao _<#=entity.Name#>Dao; public I<#=entity.Name#>Dao <#=entity.Name#>Dao { get { if (_<#=entity.Name#>Dao == null) { _<#=entity.Name#>Dao = new <#=entity.Name#>Dao(); } return _<#=entity.Name#>Dao; } set { _<#=entity.Name#>Dao = value; } } <#}#> } }
3.3保存模版并运行,T4模版会自动将所有实体对象封装为属性。如下代码所示:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using Cnblogs.Rdst.IDAO; 6 7 namespace Cnblogs.Rdst.Dao 8 { 9 public partial class DBSession : IDBSession 10 { 11 12 private INoteInfoDao _NoteInfoDao; 13 public INoteInfoDao NoteInfoDao 14 { 15 get 16 { 17 if (_NoteInfoDao == null) 18 { 19 _NoteInfoDao = new NoteInfoDao(); 20 } 21 return _NoteInfoDao; 22 } 23 set { _NoteInfoDao = value; } 24 } 25 26 private IUserInfoDao _UserInfoDao; 27 public IUserInfoDao UserInfoDao 28 { 29 get 30 { 31 if (_UserInfoDao == null) 32 { 33 _UserInfoDao = new UserInfoDao(); 34 } 35 return _UserInfoDao; 36 } 37 set { _UserInfoDao = value; } 38 } 39 } 40 }
3.4、打开刚创建的DBSession类,实现IDBSession接口。并重新SaveChanges()方法,SaveChange()方法中调用了EF上下文中的SaveChange(),
其用途会在业务逻辑层进行详细说明。
以下是DBSession类中的实现代码:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Cnblogs.Rdst.IDAO; using System.Data.Objects; namespace Cnblogs.Rdst.Dao { public partial class DBSession : IDBSession { private ObjectContext _efContext; //EF上下文 public ObjectContext EfContext { get { if (_efContext == null) { _efContext= ObjectContextFactory.GetCurrentObjectContext(); } return _efContext; } set { _efContext = value; } } public int SaveChange() { return EfContext.SaveChanges();//调用SaveChanges()方法提交操作 } } }
四、实现数据访问层统一入口
接下来现在我们需要在Cnblogs.Rdst.Dao程序集中实现IDbSessionFactory接口
创建DBSessionFactory类并实现IDbSessionFactory接口,为了避免资源浪费,也用到了CallContex实现了线程内实例唯一。
以下是DBsessionFactory类中的实现代码:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Cnblogs.Rdst.IDAO; using System.Runtime.Remoting.Messaging; namespace Cnblogs.Rdst.Dao { public class DBSessionFactory:IDBSessionFactory { public IDBSession GetCurrentDBSession() { IDBSession dbSession = CallContext.GetData(typeof(DBSessionFactory).FullName) as DBSession; if (dbSession == null) { dbSession=new DBSession(); CallContext.SetData(typeof(DBSessionFactory).FullName, dbSession); } return dbSession; } } }
至此,我们就已经完成了对数据访问层的封装。
总结:1、方便了对数据库的替换数据库,只需要在ObjectContextFactory中进行替换相应的FE上下文。
2、当数据库中的表或字段有更新时,我们只需要重新运行一下相应T4模版,就可以实现与数据库保存一致。
接下来的系列三中会介绍业务逻辑层是如何调用数据访问层,稍后会进行更新。