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容器提供 
複製代碼

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章