菜鸟级三层框架(EF+MVC)项目实战之 系列二 对数据访问层的抽象中

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

原文地址:https://www.cnblogs.com/rdst/p/2635077.html