EF6の場合
Matthiasの投稿のおかげでこの回答にたどり着きましたが、 Entity Frameworkのコードベースの構成(EF6以降)からの価値のある情報がいくつか含まれていました。
カスタムデータベースの場所を指定するには、いくつかの構成を行う必要があります。Entity Frameworkアプリケーションの構成は、構成ファイル(app.config / web.config)またはコードで指定できます。後者は、コードベースの構成として知られています。私のプロジェクトではデータベースの場所を動的に設定する必要があるため、以下で説明するコードベースの構成を使用しました。
(構成ファイルはコードベースの構成よりも優先されることに注意してください。つまり、構成オプションがコードと構成ファイルの両方で設定されている場合は、構成ファイルの設定が使用されます。)
EFのドキュメント(上記のリンク)によると、カスタム構成を実装するための4つのアプローチがあります。これには、DbConfigurationの使用、DbConfigurationの移動、DbConfigurationの明示的な設定、およびDbConfigurationのオーバーライドが含まれます。
DbConfigurationの使用
EF6以降のコードベースの構成は、System.Data.Entity.Config.DbConfigurationのサブクラスを作成することで実現されます。DbConfigurationをサブクラス化するときは、次のガイドラインに従う必要があります。
アプリケーション用にDbConfigurationクラスを1つだけ作成します。このクラスは、アプリドメイン全体の設定を指定します。
DbConfigurationクラスをDbContextクラスと同じアセンブリに配置します。(これを変更する場合は、「DbConfigurationの移動」セクションを参照してください。)
DbConfigurationクラスにパブリックパラメーターレスコンストラクターを提供します。
このコンストラクター内から保護されたDbConfigurationメソッドを呼び出して、構成オプションを設定します。
これらのガイドラインに従うことで、EFは、モデルにアクセスする必要のあるツールとアプリケーションの実行時の両方によって、構成を自動的に検出して使用できます。
例(マティアスの回答から変更):
public class MyDbConfiguration : DbConfiguration
{
public MyDbConfiguration()
{
SetProviderServices(SqlCeProviderServices.ProviderInvariantName, SqlCeProviderServices.Instance);
//var directory Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
var directory = @"C:\Users\Evan\Desktop\TestFolder"; // Directory may or may not already exist
Directory.CreateDirectory(directory); // create directory if not exists
var path = Path.Combine(directory, @"ApplicationName\MyDatabase.sdf");
var connectionString = string.Format(@"Data Source={0}",path);
SetDefaultConnectionFactory(new SqlCeConnectionFactory(SqlCeProviderServices.ProviderInvariantName, "", connectionString));
}
}
カスタム構成をオーバーライドする既存の構成設定がない限り、構成ファイルを変更する必要はないことに注意してください。また、ディレクトリを変更して、EFがまだ存在しない場合は新しいデータベースを作成できるが、親ディレクトリは作成されないことを示すために、次の行を含めました:Directory.CreateDirectory(directory)。このアプローチが私のプロジェクトで機能したことを考えると、残りの3つの構成方法については調べませんでしたが、上記のリンクでそれらの情報を見つけることができます。リンクが壊れた場合の参照として、ここにドキュメントを含めます。
DbConfigurationの移動
DbConfigurationクラスをDbContextクラスと同じアセンブリに配置できない場合があります。たとえば、それぞれ異なるアセンブリに2つのDbContextクラスがあるとします。これを処理するための2つのオプションがあります。
最初のオプションは、構成ファイルを使用して、使用する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を呼び出します。
たとえば、IDbConnectionFactoryとDbProviderServiceを置き換えるには、次のようなハンドラーを登録します。
DbConfiguration.Loaded += (_, a) =>
{
a.ReplaceService<DbProviderServices>((s, k) => new MyProviderServices(s));
a.ReplaceService<IDbConnectionFactory>((s, k) => new MyConnectionFactory(s));
};
上記のコードでは、MyProviderServicesとMyConnectionFactoryはサービスの実装を表しています。
同じ効果を得るために、依存関係ハンドラーを追加することもできます。
この方法でDbProviderFactoryをラップすることもできますが、これはEFにのみ影響し、EF外でのDbProviderFactoryの使用には影響しないことに注意してください。このため、以前と同じようにDbProviderFactoryをラップし続けることをお勧めします。
また、アプリケーションの外部で実行するサービス(たとえば、パッケージマネージャーコンソールからの移行の実行)にも注意する必要があります。コンソールからmigrateを実行すると、DbConfigurationの検索が試行されます。ただし、ラップされたサービスを取得するかどうかは、登録したイベントハンドラーの場所によって異なります。DbConfigurationの構築の一部として登録されている場合は、コードが実行され、サービスがラップされます。通常、これは当てはまりません。これは、ツールがラップされたサービスを取得しないことを意味します。