• Entity Framework在Asp.net MVC中的实现One Context Per Request(附源码)


    上篇中"Entity Framework中的Identity map和Unit of Work模式", 由于EF中的Identity map和Unit of Work模式,EF体现出来如下特性:

    唯一性: 在一个Context的生命周期中,一个Entity只会有一个实例,任何对该实例的修改,即使这些改动没有保存到数据库中,修改都会影响到整个Context的生命周期。

    事务性: 所有对于Entity的修改,都会在调用SaveChange方法的时候,一起保存到数据库中,最终实现持久化。

    下面基于EF的上面特点,分析一下为什么需要在MVC中实现One Context Per Request, 也就是在一个Request生命周期中,只有一个Context.

    阅读目录:

    一、每次创建Context的缺点

    二、使用全局Context的缺点

    三、在MVC中实现One Context Per Request

    四、借助Autofac实现One Context Per Request

    一,每次创建Context的缺点

    一般在项目的数据访问层中使用Entity Framework,代码如下

    public IEnumerable<Student> GetStudents()
    { 
           using (var context = new SchoolContext()) 
           { 
               return context.Students.ToList(); 
           } 
    }

    这个是数据访问层中非常常见的方法,返回DB中所有的Student数据。

    这里在使用Context的时候,创建一个Context的实例进行操作。

    但是这种方式带来了下面一些缺点:

    • 首先,每次的数据处理,都用new context, 会导致更多的资源开销。
    • 假如业务逻辑层调用GetStudents方法获取到数据之后,要访问Student的导航属性School怎么办? 逻辑层代码使用导航时候就会导致异常,因为EF只能在context生命周期中,才能够再次请求数据库,取得导航属性School的数据。
    • 如果是插入操作,而且是多个关联表的数据插入,插入操作在不同的context中完成,就无法应用EF的事务效果。保证数据能够同时插入成功,如果失败,就一起回滚。
    • 如果在循环中插入数据,每次插入数据都是在不同的context中完成,性能就是一个悲剧。

    二,使用全局Context的缺点

    看到了"每次创建Context”的缺点,可能会认为使用全局Context是个好的解决方案。

    但是全局Context带来的问题更大:

    • 如果全局使用一个Context,会导致越来越多的数据缓存到本地, 随着程序的使用时间越长,占用的资源越来越大。
    • 使用全局Context, 会导致缓存数据无法得到及时更新。即使数据库中的数据有改动,使用EF取出来得数据有可能还是改动之前的数据。

    所以:

    • 在MVC项目中,建议每个request, 使用一个Context
    • 在Winform中和WPF中,一个Form或者一个Presenter一个Context
    • 在WebService, Web API中,每次调用, 使用一个Context.

    三, 在MVC中实现One Context Per Request

    思路是这样的,  在Global.asax.cs文件中,在Begin Request事件中,创建和保存Context; 在End Request事件中,销毁Context. 另外提供一个公开的静态属性来获取这个Context。

    详细的代码如下:

    在Global.asax.cs中

    protected virtual void Application_BeginRequest()
    {
        HttpContext.Current.Items["_EntityContext"] = new EntityContext();
    }
    
    protected virtual void Application_EndRequest()
    {
        var entityContext = HttpContext.Current.Items["_EntityContext"] as EntityContext;
        if (entityContext != null)
            entityContext.Dispose();
    }

    添加静态属性,以便程序中能够方便的取出和使用Context

    public class EntityContext
    {
        public static EntityContext Current
        {
            get { return HttpContext.Current.Items["_EntityContext"] as EntityContext; }
        }
    }

    四,借助Autofac实现One Context Per Request

    Autofac是.net的Ioc容器,具体使用的方法,可以看这里 IoC容器Autofac(4) - Autofact + Asp.net MVC + EF Code First(附源码)

    本文的Demo源码,是在上面博客附带的源码基础上修改而来的。

    这里,只是介绍一下如何使用Autofac注册Context

    在Application_Start函数体内,执行如下代码

    var builder = new ContainerBuilder(); //创建builder
    //注册builder, 实现one context per request
    builder.RegisterType<eassistdevContext>().InstancePerHttpRequest();
    
    var container = builder.Build();//创建容器
    DependencyResolver.SetResolver(new AutofacDependencyResolver(container));//覆盖MVC默认的实例化Controller的方法,转而又Auotfac容器提供 

    更详细的过程,可以在这里直接下载源代码 AutofactMVC(One-Context-Per-Request).zip

    源代码中也使用了MiniProfler,推荐一下

  • 相关阅读:
    函数---迭代器&生成器&列表解析&三元表达式
    python函数模拟mysql增删改查功能
    装饰器
    函数----模块化的程序设计
    文件操作
    字符编码
    python的对象类型-----列表&元组&字典
    Mac上vmware虚拟机Windows10安装JDK8及配置环境
    Windows10显示桌面我的电脑等图标
    HTTP状态码:300400500 错误代码
  • 原文地址:https://www.cnblogs.com/JustRun1983/p/3249462.html
Copyright © 2020-2023  润新知