同じ DbContext 型の複数のモデルを交互に切り替える

OnModelCreating で構築されたモデルでは、コンテキストのプロパティを使用して、モデルの構築方法を変更できます。 たとえば、いくつかのプロパティに基づいて、エンティティを異なる方法で構成するとします。

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    if (UseIntProperty)
    {
        modelBuilder.Entity<ConfigurableEntity>().Ignore(e => e.StringProperty);
    }
    else
    {
        modelBuilder.Entity<ConfigurableEntity>().Ignore(e => e.IntProperty);
    }
}

残念ながら、このコードはそのまま機能しません。これは、EF はモデルを構築して OnModelCreating を 1 回だけ実行し、パフォーマンス上の理由から結果がキャッシュされるためです。 ただし、モデル キャッシュ メカニズムに接続して、さまざまなモデルを生成するプロパティを EF に認識させることができます。

IModelCacheKeyFactory

EF は、IModelCacheKeyFactory を使用してモデルのキャッシュ キーを生成します。EF は既定で、特定のコンテキスト型について、モデルが同じであることを前提としています。したがって、このサービスの既定の実装では、コンテキスト型のみを含むキーが返されます。 同じコンテキスト型から異なるモデルを生成するには、IModelCacheKeyFactory サービスを適切な実装に置き換える必要があります。生成されたキーは、モデルに影響を与えるすべての変数を考慮して、Equals メソッドを使用して他のモデル キーと比較されます。

次の実装は、モデル キャッシュ キーを生成するときに、UseIntProperty を考慮します。

public class DynamicModelCacheKeyFactory : IModelCacheKeyFactory
{
    public object Create(DbContext context, bool designTime)
        => context is DynamicContext dynamicContext
            ? (context.GetType(), dynamicContext.UseIntProperty, designTime)
            : (object)context.GetType();
}

デザイン時のモデル キャッシュも処理する Create メソッドのオーバーロードも実装する必要があります。 次の例では以下のようになります。

public class DynamicModelCacheKeyFactoryDesignTimeSupport : IModelCacheKeyFactory
{
    public object Create(DbContext context, bool designTime)
        => context is DynamicContext dynamicContext
            ? (context.GetType(), dynamicContext.UseIntProperty, designTime)
            : (object)context.GetType();

    public object Create(DbContext context)
        => Create(context, false);
}

最後に、新しい IModelCacheKeyFactory をコンテキストの OnConfiguring に登録します。

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder
        .UseInMemoryDatabase("DynamicContext")
        .ReplaceService<IModelCacheKeyFactory, DynamicModelCacheKeyFactory>();

詳細なコンテキストについては、完全なサンプル プロジェクトに関するページを参照してください。