Alterner entre plusieurs modèles avec le même type DbContext

Le modèle intégré OnModelCreating peut utiliser une propriété sur le contexte pour modifier la façon dont le modèle est généré. Par exemple, supposons que vous vouliez configurer une entité différemment en fonction de certaines propriétés :

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

Malheureusement, ce code ne fonctionnerait pas as-is, car EF génère le modèle et ne s’exécute OnModelCreating qu’une seule fois, mettant en cache le résultat pour des raisons de performances. Toutefois, vous pouvez vous connecter au mécanisme de mise en cache de modèle pour rendre EF conscient de la propriété produisant différents modèles.

IModelCacheKeyFactory

EF utilise la IModelCacheKeyFactory méthode pour générer des clés de cache pour les modèles ; par défaut, EF part du principe que, pour tout type de contexte donné, le modèle sera identique, de sorte que l’implémentation par défaut de ce service retourne une clé qui contient simplement le type de contexte. Pour produire différents modèles à partir du même type de contexte, vous devez remplacer le IModelCacheKeyFactory service par l’implémentation correcte ; la clé générée sera comparée à d’autres clés de modèle à l’aide de la Equals méthode, en tenant compte de toutes les variables qui affectent le modèle.

L'implémentation suivante prend en compte UseIntProperty lors de la production d'une clé de cache de modèle.

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

Vous devez également implémenter la surcharge de la méthode Create qui gère également la mise en cache du modèle au moment du design. Comme dans l’exemple suivant :

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);
}

Enfin, inscrivez votre nouveau IModelCacheKeyFactory dans le OnConfiguring de votre contexte :

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

Pour plus de contexte, consultez l’exemple de projet complet .