DbContext の操作

Entity Framework と .NET オブジェクトを使用してデータのクエリ、挿入、更新、削除を行うにはまず、モデルに定義したエンティティとリレーションシップをデータベースのテーブルにマッピングするモデルを作成する必要があります。

モデルの完成後に、アプリケーションが対話する主なクラスは System.Data.Entity.DbContext です (通常、コンテキスト クラスと呼ばれます)。 モデルに関連付けられた DbContext を使用して次のことができます。

  • クエリを作成して実行する
  • クエリの結果をエンティティ オブジェクトとして具体化する
  • それらのオブジェクトに加えられた変更を追跡する
  • オブジェクトの変更をデータベースに永続化する
  • メモリ内のオブジェクトを UI コントロールにバインドする

このページでは、コンテキスト クラスを管理する方法についてのガイダンスを紹介します。

DbContext 派生クラスの定義

コンテキストを操作する方法として推奨されるのは、DbContext から派生し、コンテキスト内の指定されたエンティティのコレクションを表す DbSet のプロパティを公開するクラスを定義することです。 EF Designer を使用する場合、コンテキストは自動的に生成されます。 Code First を使用する場合は、通常、開発者が自分でコンテキストを作成します。

public class ProductContext : DbContext
{
    public DbSet<Category> Categories { get; set; }
    public DbSet<Product> Products { get; set; }
}

コンテキストの取得後は、そのプロパティを通じて、コンテキストのエンティティを照会したり、追加 (Add または Attach メソッドを使用) したり、削除 (Remove を使用) したりすることになります。 コンテキスト オブジェクトの DbSet プロパティにアクセスすることは、指定した型のすべてのエンティティを取得するクエリを開始することに相当します。 ただしプロパティにアクセスするだけでは、クエリは実行されません。 クエリは次の場合に実行されます。

  • foreach (C#) または For Each (Visual Basic) ステートメントによって列挙された場合。
  • ToArrayToDictionaryToList などのコレクション操作によって列挙された場合。
  • FirstAny などの LINQ 演算子がクエリの最も外側で指定された場合。
  • 指定したキーのエンティティがコンテキストに読み込み済みであることが確認できなかった場合に、Load 拡張メソッド、DbEntityEntry.ReloadDatabase.ExecuteSqlCommandDbSet<T>.Find のいずれかのメソッドが呼び出されたとき。

有効期限

コンテキストの有効期間は、インスタンスが作成された時点から、インスタンスが破棄またはガベージ コレクトされた時点までです。 コンテキストが制御するすべてのリソースをブロックの最後に破棄する場合、using を使用します。 using を使用する際、コンパイラは try/finally ブロックを作成し、finally ブロックで dispose を呼び出します。

public void UseProducts()
{
    using (var context = new ProductContext())
    {     
        // Perform data access using the context
    }
}

コンテキストの有効期間を決定する際のいくつかの一般的なガイドラインを示します。

  • Web アプリケーションを使用する場合、要求ごとにコンテキスト インスタンスを使用します。
  • Windows Presentation Foundation (WPF) または Windows フォームを使用する場合、フォームごとにコンテキスト インスタンスを使用します。 これで、コンテキストが提供する変更追跡機能を使用できます。
  • コンテキスト インスタンスが依存関係挿入コンテナーによって作成された場合、通常、コンテキストを破棄するのはコンテナーの役割となります。
  • アプリケーション コードでコンテキストを作成した場合は、不要になったコンテキストを忘れずに破棄してください。
  • 実行時間の長いコンテキストを使用する場合、次の点に注意してください。
    • メモリに読み込むオブジェクトとそれらの参照が多いほど、コンテキストのメモリ消費は急速に増大します。 これは、パフォーマンスを低下させる原因になります。
    • コンテキストはスレッドセーフではないため、複数のスレッドで共有して同時に操作することは避けてください。
    • 例外によってコンテキストが回復不能な状態になると、アプリケーション全体が終了する場合があります。
    • データの照会時と更新時の時間差が大きくなると、コンカレンシーに関する問題が生じる可能性が高くなります。

接続

既定では、コンテキストがデータベースへの接続を管理します。 コンテキストが必要に応じて接続を開閉します。 たとえば、コンテキストは接続を開いてクエリを実行し、すべての結果セットが処理されると接続を閉じます。

接続の開閉をより詳細に制御する必要がある場合もあります。 たとえば、SQL Server Compact を使用しているときは、多くの場合、パフォーマンスを高めるために、アプリケーションの有効期間中、データベースに対して開いた単独の接続を維持することをお勧めします。 Connection プロパティを使用することにより、手動でこのプロセスを管理できます。