コードベースの構成

Note

EF6 以降のみ - このページで説明する機能、API などは、Entity Framework 6 で導入されました。 以前のバージョンを使用している場合、一部またはすべての情報は適用されません。

Entity Framework アプリケーションの構成は、構成ファイル (app.config または web.config) またはコードで指定できます。 後者は、コードベースの構成と呼ばれています。

構成ファイルでの構成については、別の記事で説明しています。 構成ファイルは、コードベースの構成よりも優先されます。 つまり、コードと構成ファイルの両方で構成オプションが設定されている場合、構成ファイルの設定が使用されます。

DbConfiguration の使用

EF6 以降でコードベースの構成を行うには、System.Data.Entity.Config.DbConfiguration のサブクラスを作成します。 DbConfiguration のサブクラスを作成する際は、次のガイドラインに従う必要があります。

  • アプリケーションに使用する DbConfiguration クラスを 1 つだけ作成します。 アプリ ドメイン全体の設定をこのクラスで指定します。
  • DbContext クラスと同じアセンブリに DbConfiguration クラスを配置します。 (これを変更したい場合は、「DbConfiguration を移動する」セクションを参照してください。)
  • DbConfiguration クラスに、パラメーターなしのパブリック コンストラクターを記述します。
  • このコンストラクター内から protected DbConfiguration メソッドを呼び出して構成オプションを設定します。

これらのガイドラインに従うことで、モデルにアクセスする必要のあるツールによって、また、アプリケーションの実行時に、必要な構成を EF が自動的に検出して使用できるようになります。

以下に示したのは、DbConfiguration から派生したクラスの例です。

using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.SqlServer;

namespace MyNamespace
{
    public class MyConfiguration : DbConfiguration
    {
        public MyConfiguration()
        {
            SetExecutionStrategy("System.Data.SqlClient", () => new SqlAzureExecutionStrategy());
            SetDefaultConnectionFactory(new LocalDbConnectionFactory("mssqllocaldb"));
        }
    }
}

このクラスは、失敗したデータベース操作を自動的に再試行する SQL Azure 実行戦略を使用し、Code First から規約により作成されるデータベースにローカル DB を使用するように EF を設定します。

DbConfiguration を移動する

DbContext クラスと同じアセンブリに DbConfiguration クラスを配置できないケースもあります。 たとえば、2 つの DbContext クラスがそれぞれ異なるアセンブリに存在する場合があります。 この場合、2 つの対処法があります。

1 つ目は、使用する DbConfiguration インスタンスを構成ファイルで指定する方法です。 そのためには、entityFramework セクションの codeConfigurationType 属性を設定します。 次に例を示します。

<entityFramework codeConfigurationType="MyNamespace.MyDbConfiguration, MyAssembly">
    ...Your EF config...
</entityFramework>

codeConfigurationType の値には、DbConfiguration クラスのアセンブリと名前空間の修飾名を指定する必要があります。

2 つ目は、DbConfigurationTypeAttribute をコンテキスト クラスで設定する方法です。 次に例を示します。

[DbConfigurationType(typeof(MyDbConfiguration))]
public class MyContextContext : DbContext
{
}

この属性の値には、DbConfiguration 型 (上記) を渡すか、またはアセンブリと名前空間の修飾型名文字列を渡すことができます。 次に例を示します。

[DbConfigurationType("MyNamespace.MyDbConfiguration, MyAssembly")]
public class MyContextContext : DbContext
{
}

DbConfiguration を明示的に設定する

いくつかの状況では、DbContext 型が使用される前に構成が必要となる場合があります。 この例には以下のようなものがあります。

  • DbModelBuilder を使用して、コンテキストなしでモデルを作成する
  • その他、DbContext を利用するなんらかのフレームワークまたはユーティリティ コードを使用する際、そのコンテキストが、自分のアプリケーションのコンテキストよりも前に使用される

このような状況では EF が構成を自動的に検出できないため、次のいずれかの操作を手動で行う必要があります。

  • 構成ファイルで DbConfiguration 型を設定する (前出の「DbConfiguration を移動する」セクションを参照)
  • アプリケーションの起動中に DbConfiguration.SetConfiguration 静的メソッドを呼び出す

DbConfiguration をオーバーライドする

いくつかの状況では、DbConfiguration で設定された構成をオーバーライドする必要があります。 通常、これを行うのはアプリケーション開発者ではなく、派生 DbConfiguration クラスを使用できないプラグインやサード パーティのプロバイダーです。

この目的のために、EntityFramework では、イベント ハンドラーを登録して、既存の構成がロック ダウンされる前に、それを変更できるようになっています。 EF サービス ロケーターから返されたサービスを置き換えることに特化した便利なメソッドも用意されています。 次のような使い方が意図されています。

  • アプリの起動時 (EF が使用される前) に、プラグインまたはプロバイダーは、このイベントのイベント ハンドラー メソッドを登録する必要があります。 (この処理は、アプリケーションによって EF が使用される前に行う必要があります。)
  • 置き換えを必要とする各サービスについて、イベント ハンドラーが ReplaceService を呼び出します。

たとえば、IDbConnectionFactoryDbProviderService を置き換えたければ、このようなハンドラーを登録することになります。

DbConfiguration.Loaded += (_, a) =>
   {
       a.ReplaceService<DbProviderServices>((s, k) => new MyProviderServices(s));
       a.ReplaceService<IDbConnectionFactory>((s, k) => new MyConnectionFactory(s));
   };

上記のコードでは、MyProviderServicesMyConnectionFactory が実際のサービスの実装を表します。

さらに依存関係のハンドラーを追加して、同様の効果を実現することもできます。

この方法で DbProviderFactory をラップすることもできますが、その作用が及ぶのは EF のみであり、EF の外部における DbProviderFactory の使用には作用しないことに注意してください。 このような理由から、おそらく DbProviderFactory は今後も、以前と同じようにラップすることになるでしょう。

また、パッケージ マネージャー コンソールから移行を実行する場合など、アプリケーションの外部で実行するサービスにも注意を払う必要があります。 コンソールから移行を実行すると、DbConfiguration の検索が試みられます。 しかしサービスがラップされるかどうかは、イベント ハンドラーがどこで登録されるかによって異なります。 DbConfiguration が構築される過程で登録されれば、コードが実行され、サービスはラップされます。 通常、そのようなケースに該当することはなく、そうなると当然、サービスはラップされません。