42 votes

Confusion sur les migrations automatiques EF et l'ensemencement - ensemencement à chaque démarrage de programme

J'ai récemment modifié une application qui utilisait les éléments suivants pour le développement :

DropCreateDatabaseIfModelChanges<Context>

A utiliser :

public class MyDbMigrationsConfiguration: DbMigrationsConfiguration<GrsEntities>
{
    public MyDbMigrationsConfiguration()
    {
        AutomaticMigrationsEnabled = true;
        AutomaticMigrationDataLossAllowed = true;
    }
}

Dans mon contexte de db, j'ai :

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    // Tell Code First to ignore PluralizingTableName convention
    // If you keep this convention then the generated tables will have pluralized names.
    modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();

    //set the initializer to migration
    Database.SetInitializer(new MigrateDatabaseToLatestVersion<GrsEntities, MigrationConfig>());
}

J'ai surchargé Seed(context) dans DbMigrationsConfiguration en utilisant l'extension AddOrUpdate alors que je n'utilisais que Add auparavant avec l'ensemencement sur le drop db (DropCreateDatabaseIfModelChanges).

Le problème est que la migration s'exécute à chaque démarrage de l'application, sans qu'il y ait de changement dans le DbContext. Chaque fois que je démarre l'application (bibliothèque exécutée par un service), l'initialisateur s'exécute ainsi que le Seed. Je m'attends à ce qu'il vérifie si une migration est nécessaire (en coulisse, il vérifie si le modèle correspond à la base de données physique), puis qu'il mette à jour toutes les tables/colonnes nouvelles/supprimées et qu'il n'exécute Seed que si quelque chose a changé.

Dans mes tests, les semences sont exécutées à chaque fois, ce qui est faisable mais semble inefficace et n'est pas ce que j'attendais. Malheureusement, la documentation MSDN est assez limitée.

Est-ce que je fais une mauvaise utilisation de MigrateDatabaseToLatestVersion ? Y a-t-il un moyen d'obtenir le comportement que j'attends (c.-à-d. ensemencer seulement s'il y a un changement de modèle) ou dois-je simplement changer ma méthode d'ensemencement pour qu'elle s'attende à être exécutée à chaque lancement d'application ?

61voto

Arthur Vickers Points 4894

Le fait que la méthode Seed ne s'exécute que lorsque la base de données est modifiée était assez limitatif pour les initialisateurs de base de données livrés avec EF 4.1. En effet, il était parfois nécessaire de mettre à jour les données d'initialisation sans modifier la base de données, mais pour cela, il fallait faire croire artificiellement que la base de données avait changé.

Avec les migrations, l'utilisation de Seed est devenue un peu différente car on ne pouvait plus supposer que la base de données était vide au départ - c'est un peu le but des migrations après tout. Ainsi, une méthode Seed dans les Migrations doit supposer que la base de données existe et peut déjà contenir des données, mais que ces données peuvent avoir besoin d'être mises à jour pour prendre en compte les changements apportés à la base de données pour les Migrations. D'où l'utilisation de AddOrUpdate.

Nous sommes donc maintenant dans une situation où Seed doit être écrit pour prendre en compte les données existantes, ce qui signifie qu'il n'y a pas vraiment besoin de perpétuer les limitations de la méthode Seed de EF 4.1 telles que vous devriez faire croire que la base de données a changé juste pour que Seed fonctionne. Ainsi, Seed s'exécute désormais à chaque fois que le contexte est utilisé pour la première fois dans le domaine de l'application. Cela ne devrait pas changer la façon dont Seed est implémenté puisqu'il doit gérer le cas où les données sont déjà présentes de toute façon.

Si cela pose des problèmes de perforation parce que vous avez beaucoup de données Seed, il est généralement facile d'ajouter des contrôles dans la méthode Seed qui interrogent la base de données pour déterminer la quantité de travail à effectuer avant de le faire.

0 votes

Merci Arthur. C'était clair, concis et juste ce que je cherchais. J'avais fini par changer ma graine pour supposer qu'elle s'exécuterait à chaque fois, mais il est bon de connaître l'histoire derrière cela (que je n'ai pas pu trouver).

9 votes

Le fait que la méthode d'ensemencement ne s'exécutait que lorsqu'une migration avait lieu et qu'elle s'exécute maintenant chaque fois que le contexte est utilisé pour la première fois est très déroutant. Existe-t-il un article MSDN qui détaille ce changement ?

18voto

GLM Points 868

Je suis quelque peu d'accord avec Arthur Vickers Si j'ai 4 migrations, j'aurais besoin de tester d'une manière ou d'une autre quelles données doivent être ensemencées et cela représenterait au moins 4 visites supplémentaires de la base de données. Au cas où vous souhaiteriez toujours avoir le comportement de la méthode Seed uniquement lorsque les migrations sont appliquées, comme moi, j'ai créé ma propre implémentation de la méthode Seed. IDatabaseInitializer stratégie

public class CheckAndMigrateDatabaseToLatestVersion<TContext, TMigrationsConfiguration>
    : IDatabaseInitializer<TContext>
    where TContext : DbContext
    where TMigrationsConfiguration : DbMigrationsConfiguration<TContext>, new()
{
    public virtual void InitializeDatabase(TContext context)
    {
        var migratorBase = ((MigratorBase)new DbMigrator(Activator.CreateInstance<TMigrationsConfiguration>()));
        if (migratorBase.GetPendingMigrations().Any())
            migratorBase.Update();
    }
}

2voto

Une autre option pourrait être de charger une classe d'initialisation de la base de données personnalisée au moment de l'exécution dans la méthode d'amorçage. L'application de production pourrait alors charger un initialisateur factice, tandis que l'application de développement pourrait charger l'initialisateur réel. Vous pourriez utiliser Unity/MEF

    // Unity Dependency Injection Prop
    [Dependency]
    property IMyInitializer initializer;

    protected override Seed(YourContextClass context)
    {
       initializer.Seed(context);
    }

Quelque chose comme ça. Une fois la base de données configurée en production, vous basculerez les initialisateurs vers la base factice, qui ne fera rien.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X