41 votes

Meilleure façon d'ensemencer les données de façon incrémentielle dans Entity Framework 4.3

J'ai utilisé Entity Framework 4.3 sur une base de données existante et j'essaie de répondre à un certain nombre de scénarios.

Tout d'abord, si je supprime ma base de données, je voudrais que EF la recrée à partir de zéro. J'ai utilisé avec succès un initialisateur de base de données CreateDatabaseIfNotExists pour cela.

Deuxièmement, si je mets à jour mon modèle et que la base de données existe déjà, je voudrais que la base de données soit mise à jour automatiquement - j'ai utilisé avec succès Entity Framework 4.3 Migrations pour cela.

Voici donc ma question. Disons que j'ajoute une nouvelle table à mon modèle qui nécessite des données de référence, quelle est la meilleure façon de s'assurer que ces données sont créées à la fois lorsque l'initialisateur de base de données s'exécute et lorsque la migration s'exécute. Je souhaite que les données soient créées lorsque je crée la base de données à partir de zéro et également lorsque la base de données est mise à jour à la suite d'une migration.

Dans certains exemples de migrations EF, j'ai vu des personnes utiliser la fonction SQL() dans la méthode UP de la migration pour créer des données d'amorçage, mais si possible, je préférerais utiliser le contexte pour créer les données d'amorçage (comme on le voit dans la plupart des exemples d'initialisation de base de données), car il me semble étrange d'utiliser du sql pur alors que l'idée même d'EF est d'abstraire cela. J'ai essayé d'utiliser le contexte dans la méthode UP, mais pour une raison quelconque, il ne pensait pas qu'une table créée lors de la migration existait lorsque j'ai essayé d'ajouter les données d'amorçage directement sous l'appel à la création de la table.

Tout conseil est le bienvenu.

55voto

Ladislav Mrnka Points 218632

Si vous voulez utiliser des entités pour ensemencer des données, vous devez utiliser Seed dans la configuration de vos migrations. Si vous générez un nouveau projet Enable-Migrations vous obtiendrez cette classe de configuration :

internal sealed class Configuration : DbMigrationsConfiguration<YourContext>
{
    public Configuration()
    {
        AutomaticMigrationsEnabled = false;
    }

    protected override void Seed(CFMigrationsWithNoMagic.BlogContext context)
    {
        //  This method will be called after migrating to the latest version.

        //  You can use the DbSet<T>.AddOrUpdate() helper extension method 
        //  to avoid creating duplicate seed data. E.g.
        //
        //    context.People.AddOrUpdate(
        //      p => p.FullName,
        //      new Person { FullName = "Andrew Peters" },
        //      new Person { FullName = "Brice Lambson" },
        //      new Person { FullName = "Rowan Miller" }
        //    );
        //
    }
}

La façon dont les migrations ensemencent les données n'est pas très efficace car elle est censée être utilisée pour un ensemencement très basique. Chaque mise à jour de la nouvelle version passera par l'ensemble du jeu et essaiera de mettre à jour les données existantes ou d'insérer de nouvelles données. Si vous n'utilisez pas AddOrUpdate méthode d'extension, vous devez vous assurer manuellement que les données ne sont introduites dans la base de données que si elles ne sont pas encore présentes.

Si vous voulez un moyen efficace pour l'ensemencement parce que vous devez ensemencer beaucoup de données, vous obtiendrez de meilleurs résultats avec le commun :

public partial class SomeMigration : DbMigration
{
    public override void Up()
    {
        ...
        Sql("UPDATE ...");
        Sql("INSERT ...");
    }

    public override void Down()
    {
        ...
    }
}

32voto

Roger Points 785

Je ne recommanderais pas d'utiliser Sql() appels dans votre Up() car (IMO) cette méthode est vraiment destinée au code de migration réel pour lequel il n'existe pas de fonction intégrée, plutôt qu'au code d'amorçage.

J'aime penser aux données d'ensemencement comme à quelque chose qui pourrait changer à l'avenir (même si mon schéma ne change pas), donc j'écris simplement des vérifications "défensives" autour de toutes mes insertions dans la fonction d'ensemencement pour m'assurer que l'opération n'a pas été exécutée auparavant.

Prenons l'exemple d'une table "Types" qui commence par trois entrées, puis en ajoute une quatrième. Vous ne devriez pas avoir besoin d'une "migration" pour résoudre ce problème.

Utilisation de Seed() vous donne également un contexte complet avec lequel travailler, ce qui est beaucoup plus agréable que d'utiliser les chaînes de caractères sql simples dans le fichier Sql() la méthode que Ladislav a démontrée.

Gardez également à l'esprit que l'avantage d'utiliser des méthodes EF intégrées à la fois pour le code de migration et le code d'amorçage est que vos opérations de base de données restent indépendantes de la plate-forme. Cela signifie que vos modifications de schéma et vos requêtes peuvent être exécutées sur Oracle, Postgre, etc. Si vous écrivez du SQL brut, vous risquez de vous enfermer inutilement.

Vous êtes peut-être moins concerné par ce point puisque 90% des personnes qui utilisent EF ne toucheront jamais que le serveur SQL, mais je le lance juste pour vous donner une perspective différente de la solution.

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