Entity FrameworkはAspにあります.NetMVCでの実装One Context Per Request(付源コード)


前編「Entity FrameworkのIdentity mapおよびUnit of Workモード」では、EFのIdentity mapとUnit of Workモードのため、EFは以下の特性を体現している.
≪一意性|Uniqueness|emdw≫:1つのContextのライフサイクルで、1つのEntityには1つのインスタンスしかありません.このインスタンスに対する変更は、データベースに保存されていなくても、Contextのライフサイクル全体に影響します.
トランザクション:Entityに対するすべての変更は、SaveChangeメソッドが呼び出されたときにデータベースに一緒に保存され、最終的に永続化されます.
以下、EFの上記の特徴に基づいて、MVCでOne Context Per Requestを実現する必要がある理由を分析する.すなわち、1つのRequestライフサイクルの中で、1つの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内のすべてのStudioデータを返します.
ここでContextを使用する場合は、Contextのインスタンスを作成して操作します.
しかし、この方法は以下の欠点をもたらしました.
  • まず、データ処理のたびにnew contextを使用すると、より多くのリソースオーバーヘッドが発生します.
  • ビジネスロジック層がGetStudioメソッドを呼び出してデータを取得した後、Studioのナビゲーション属性Schoolにアクセスするにはどうすればいいですか?論理層コードがナビゲーションを使用する場合、EFはcontextライフサイクル中にのみデータベースを再要求し、ナビゲーション属性Schoolのデータを取得することができるため、異常が発生します.
  • 挿入操作であり、かつ複数の関連テーブルのデータ挿入であれば、挿入操作が異なるcontextで完了すると、EFのトランザクション効果は適用されません.データの同時挿入に成功することを保証し、失敗したら一緒にロールバックします.
  • ループにデータを挿入すると、データを挿入するたびに異なるcontextで完了し、パフォーマンスは悲劇です.

  • 二、グローバルContextを使用する欠点


    「Contextを作成するたびに」という欠点が見られ、グローバルContextを使用するのが良い解決策だと思われるかもしれません.
    しかし、グローバルContextがもたらす問題はもっと大きい.
  • グローバルにContextを使用すると、ローカルにキャッシュされるデータが増え、プログラムの使用時間が長くなるにつれて、消費されるリソースが大きくなります.
  • グローバルContextを使用すると、キャッシュデータがタイムリーに更新されなくなります.データベース内のデータが変更されても,EFを用いて取り出されたデータは変更前のデータである可能性がある.

  • したがって、
  • MVCプロジェクトではrequestごとにContext
  • を使用することを推奨します.
  • Winform中和WPFにおいて、1つのFormまたは1つのPresenter 1つのContext
  • WebService,Web APIでは、呼び出すたびにContextを1つ使用する.

  • 三、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.NetMVC+EF Code First(ソースコード付)
    本文のDemoソースは、上のブログに添付されているソースコードを元に修正したものです.
    ここでは、Autofacを使用してContextを登録する方法について説明します.
    アプリケーション_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が使われていますので、お勧めします