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

Le modèle conçu dans OnModelCreating peut utiliser une propriété sur le contexte pour changer la conception du modèle. Par exemple, supposons que vous souhaitiez configurer une entité de manière différente en fonction d’une propriété :

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 fonctionnera pas tel quel, car EF conçoit le modèle et exécute OnModelCreating une seule fois, mettant en cache le résultat pour des raisons de performances. Toutefois, vous pouvez vous raccorder au mécanisme de mise en cache du modèle pour faire connaître à EF la propriété générant divers modèles.

IModelCacheKeyFactory

EF utilise IModelCacheKeyFactory pour générer des clés de cache pour des modèles. Par défaut, EF suppose que pour un type de contexte donné, le modèle est le même pour que l’implémentation par défaut de ce service retourne une clé qui ne contient que le type de contexte. Pour générer plusieurs modèles à partir du même type de contexte, vous devez remplacer le service IModelCacheKeyFactory par l’implémentation correcte. La clé générée est comparée à d’autres clés de modèle en utilisant la méthode Equals en prenant en compte toutes les variables qui affectent le modèle.

L’implémentation suivante prend en compte UseIntProperty lors de la génération 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 Créer qui gère également la mise en cache de 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 nouvelle IModelCacheKeyFactory dans OnConfiguring de votre contexte :

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

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