• 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,推荐一下

  • 相关阅读:
    商贸通帐套隐藏方法
    固定资产打开提示:上年度数据未结转!
    ZOJ 2432 Greatest Common Increasing Subsequence
    POJ 1080 Human Gene Functions
    POJ 1088 滑雪
    POJ 1141 Brackets Sequence
    POJ 1050 To the Max
    HDOJ 1029 Ignatius and the Princess IV
    POJ 2247 Humble Numbers
    HDOJ 1181 变形课
  • 原文地址:https://www.cnblogs.com/JustRun1983/p/3249462.html
Copyright © 2020-2023  润新知