Entity Framework在Asp.net MVC中的實現One Context Per Request(轉)

上篇中"Entity Framework中的Identity map和Unit of Work模式", 因爲EF中的Identity map和Unit of Work模式,EF體現出來以下特性:html

惟一性: 在一個Context的生命週期中,一個Entity只會有一個實例,任何對該實例的修改,即便這些改動沒有保存到數據庫中,修改都會影響到整個Context的生命週期。數據庫

事務性: 全部對於Entity的修改,都會在調用SaveChange方法的時候,一塊兒保存到數據庫中,最終實現持久化。緩存

下面基於EF的上面特色,分析一下爲何須要在MVC中實現One Context Per Request, 也就是在一個Request生命週期中,只有一個Context.函數

閱讀目錄:性能

1、每次建立Context的缺點ui

2、使用全局Context的缺點spa

3、在MVC中實現One Context Per Request.net

4、藉助Autofac實現One Context Per Requestcode

一,每次建立Context的缺點

通常在項目的數據訪問層中使用Entity Framework,代碼以下orm

複製代碼
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容器提供 
複製代碼
相關文章
相關標籤/搜索