上篇中"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
一般在项目的数据访问层中使用Entity Framework,代码如下
public IEnumerable<Student> GetStudents() { using (var context = new SchoolContext()) { return context.Students.ToList(); } }
这个是数据访问层中非常常见的方法,返回DB中所有的Student数据。
这里在使用Context的时候,创建一个Context的实例进行操作。
但是这种方式带来了下面一些缺点:
看到了"每次创建Context”的缺点,可能会认为使用全局Context是个好的解决方案。
但是全局Context带来的问题更大:
所以:
思路是这样的, 在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是.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,推荐一下