マイクロソフト系技術情報 Wiki」は、「Open棟梁Project」,「OSSコンソーシアム .NET開発基盤部会」によって運営されています。

目次

概要

Entity Framework の懸念に対する調査結果。

Entity Frameworkのメモリ使用量の例

  • ユーザー定義のDbContext?を生成
  • SqlQuery?メソッドで最小限のデータを取得
  • DbContext?へ格納
  • DbContext?のライフタイムの管理

ユーザー定義のDbContext?

例えば、ProductContext?クラスは

  • DbContext?クラスから派生する必要がある。
  • DbSet?のプロパティを含める必要がある。
  • DbSet?プロパティは、コンテキストで指定されたエンティティのコレクションを表す。
public class ProductContext : DbContext
{
  public DbSet<Category> Categories { get; set; }
  • Entity Framework Designer を使用している場合、
    コンテキストは、Visual Studioのテンプレートによって自動的に生成される。
  • コードファーストテクニックを使用している場合は、手動でコンテキストを作成する。

DbContext?のライフタイム

メモリのデータ保持は、DbContext?オブジェクト インスタンスのライフタイムと同じ。

以下のように、usingを使うと、ライフタイムは明確になる。

using (ProductContext context = new ProductContext()) 
{ 
  // Perform data access using the context
}

SqlQuery?メソッド

using (ProductContext context = new ProductContext())
{
  // Below code is enumerated using ToList() method. 
  // Stores all records in “myCategories” object (Memory)
  IList<Category> myCategories =
  context.Database.SqlQuery<Category>("Select * from Category").ToList();
}

SaveChanges?メソッド使用時のコネクションやトランザクション

  • 各トランザクションのための新しい接続を作成する。
  • SaveChanges?メソッドが呼び出されたとき内部でトランザクションを維持する。
  • 一回のSaveChanges?メソッドで複数エンティティ更新のトランザクションを維持する。

Entity Framework 5.0およびそれ以前のバージョン

TransactionScope

TransactionScopeを使用してトランザクションを処理する。

using (EntitiesContext context = new EntitiesContext())
{  
  using (TransactionScope scope = new TransactionScope())
  {
    //Code here
  }
}

手動の制御も可能

ASP.NET MVCでDbContext?のトランザクションと
独自SQL 処理のトランザクションを同一のスコープにする
http://blog.makotoishida.com/2012/12/aspnet-mvcdbcontextsql.html

Entity Framework 6.0

トランザクションを維持するために、2つの新しいAPIを導入している。

DbContext?.Database.BeginTransaction? API

  • トランザクションを開始する。
  • トランザクションの分離レベルを指定することができる。
  • いくつかの操作を組み合わせて、同じトランザクション内で結合することができる。
  • したがって、全てのトランザクションをコミットまたはロールバックすることができる。
using (EntitiesContext context = new EntitiesContext())
{
  using (var transaction = context.Database.BeginTransaction())
  {
    try
    {
      EmployeeMaster employee = new EmployeeMaster();

      employee.Code = "A0001";
      employee.Name = "Jignesh Trivedi";
      employee.DepartmentId = 1;

      context.Employees.Add(employee);
      context.SaveChanges();

      DepartmentMaster dept = new DepartmentMaster();

      dept.Code = "DEP0001";
      dept.Name = "Department 1";

      context.Departments.Add(dept);
      context.SaveChanges();

      transaction.Commit();
    }
    catch (Exception ex)
    {
      transaction.Rollback();
    }
  }
} 

DbContext?.Database.UseTransaction? API

  • Entity Framework外で明記されたトランザクションを使用するDbContext?インスタンスを許可する。
  • Entity Frameworkで、このAPIを使用し任意の既存トランザクションを使用することができる。
using (SqlConnection con = new SqlConnection("connectionString"))
{
  con.Open();
  using (var transaction = con.BeginTransaction())
  {
    // Do something....  

    //Pass this transaction to Entity Framework....  
    using (EntitiesContext context = new EntitiesContext(con, false))
    {
      context.Database.UseTransaction(transaction);
      EmployeeMaster employee = new EmployeeMaster();
      employee.Code = "A0001";
      employee.Name = "Jignesh Trivedi";
      employee.DepartmentId = 1;
      context.Employees.Add(employee);

      context.SaveChanges();
    }
  }
} 

ExecuteSqlCommand?メソッドの実行時の挙動

Entity Frameworkで更新処理を実行する場合、
基本的には、SaveChanges?メソッドを使用する。

ExecuteSqlCommand?実行後、エンティティとDBは不一致状態に陥る

ExecuteSqlCommand?メソッドは、

  • コンテキスト内のエンティティの内容に関係なく、
    INSERT、UPDATE、DELETEなどのクエリを実行できる。
  • このためExecuteSqlCommand?メソッドの実行後は、
    エンティティとDBの内容は一致していない。
  • 従って、エンティティとDBの内容を一致させる必要がある場合、
    コンテキスト内のエンティティをリフレッシュする必要がある。

エンティティをリフレッシュする方法(エンティティとDBの同期)

エンティティをデタッチし再度問い合わせる。

((IObjectContextAdapter)context).ObjectContext.Detach(myCategory);

Refreshメソッドでリフレッシュする。

ObjectContext context = ((IObjectContextAdapter)myDbContext).ObjectContext;
// Refresh specific Entity object in the context
context.Refresh(System.Data.Objects.RefreshMode.StoreWins, myCategory);

(OR)

// Refresh All Entities in the context.
var refreshableObjects = myDbContext.ChangeTracker.Entries().Select(c => c.Entity).ToList();
context.Refresh(System.Data.Objects.RefreshMode.StoreWins, refreshableObjects);

Entity Data Model(以下EDM)のベスト・プラクティス

更新処理

  • EDMを複数のエンティティに統合した場合、
    単一のSaveChanges?メソッドの呼び出しで容易に複数のエンティティの更新が可能。
  • EDMを複数のエンティティに分割した場合、
    SaveChanges?メソッドを複数回呼び出す必要があり、接続とトランザクションの明示的な管理が必要。

EDMのサイズ

DBに、50~100のテーブルが含まれている場合、
すべてのエンティティを含む1つの大きなEDMを持つことは良い方法ではない。

複数エンティティを単一EDMに結合する

複数エンティティを1つの大きいEDMに集約すると、下記のようないくつかの問題を起こす。

  • 性能の問題
    • メタデータロード時間の性能
    • ビュー生成における性能
  • 雑然とする。
    • デザイナー
    • インテリセンス
    • CLRネームスペース

EDMを任意の単位に分割

上記を回避するため、
ベスト・プラクティスは任意の単位にEntity Dataモデルを分割する方法である。

動的SQLを実装する方法

https://github.com/OpenTouryoProject/SampleProgram/issues/3

System.Linq.Dynamic

Expression Tree

context.Database.SqlQuery?

参考

キャッシュの問題

Entity Dataモデルのサイズ

性能


Tags: :.NET開発, :データアクセス, :ADO.NET, :Entity Framework, :性能


トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2019-05-07 (火) 10:19:24 (71d)