web-dev-qa-db-fra.com

Pourquoi l'étape d'ajout de migration EF Migrations EF d'Entity Framework requiert-elle une chaîne de connexion à la base de données?

J'essaie d'utiliser et de comprendre les migrations EF (en utilisant EF 4.3.1, Code d'abord). Pour échafauder un nouveau changement, je dois utiliser une commande comme celle-ci:

Add-Migration MyMigration
   -ConnectionString "Data Source=.;Initial Catalog=mydb;" 
   -ConnectionProviderName "System.Data.SqlClient"
   -StartUpProjectName MyWebsite 
   -ProjectName MyEF.Migrations

Pourquoi Add-Migration nécessite-t-il des données de chaîne de connexion? Update-Database en a besoin, c'est logique. Mais Add-Migration ne dispose-t-il pas de tout ce dont il a besoin de DbContext et de la configuration?

Ce n'est pas simplement une merveille d'inactivité, c'est très déroutant de lui donner une base de données, car nous avons une solution "multi-tenant" où la base de données souhaitée est flexible et peut changer d'une requête à l'autre, sans parler du temps de compilation statique. Donc, si Add-Migration utilise réellement cette base de données pour quoi que ce soit, nous avons un problème.

MISE À JOUR: Nous avons abandonné les migrations EF et utilisons plutôt Fluent Migrator à la place, et sommes heureux. C'est beaucoup, beaucoup plus rapide, même en comptant le fait que nous devons écrire deux choses (une pour l'objet EF et une autre pour la migration), et les problèmes abordés dans cette question ne se posent pas.

24
Scott Stafford

Add-Migration vérifie l'existence de la base de données et interagit avec la table __MigrationHistory. Comme @Anders Abel l'a mentionné, il est utilisé pour enquêter sur les migrations en attente et également pour sélectionner le modèle précédent afin de déterminer ce qui a changé. Ceci est particulièrement important si vous ajoutez une migration explicite dans une solution où les migrations automatiques sont activées.

12
Ladislav Mrnka

J'ai eu de la curiosité en lisant votre question et j'ai donc lancé un outil de génération de serveurs SQL pour examiner ce qui se passe lors de l'exécution de add-migration. Il se connecte bien à la base de données et accède à la base de données pour vérifier la table __MigrationHistory.

Ceci est également illustré par le message d'erreur généré lors de la tentative de création d'une seconde migration basée sur un code sans exécuter la première:

Impossible de générer une migration explicite car les suivants des migrations explicites sont en attente: [201205291928386_foo]. Appliquer le en attente de migrations explicites avant de tenter de générer un nouveau fichier migration explicite.

Je pense que le moteur de migration utilise le modèle sérialisé de la base de données pour calculer les étapes de migration à inclure dans la nouvelle migration.

Autant que je sache, la base de données sert uniquement d’aide à la génération de code. Tant que toutes les bases de données que vous utilisez sont compatibles avec le modèle dans le code, cela ne devrait pas être un problème pour vous.

Modifier

Comme @Ladislav Mrnka le fait remarquer, une vérification de la base de données est nécessaire si les migrations sont basées sur du code et des migrations automatiques. Lorsque vous échafaudez une nouvelle migration, elle doit inclure tout ce qui a changé dans votre modèle depuis la dernière migration. Si vous utilisez des migrations automatiques, celles-ci ne sont pas suivies dans le code. Lors du calcul des modifications à inclure dans la migration, la dernière migration est utilisée comme base. La seule façon de vérifier cela est la base de données, car les migrations automatiques peuvent être activées.

Si vous utilisez uniquement des migrations basées sur du code (ce qui, à mon avis, est la seule option pour garder le contrôle), cette base de données peut alors être considérée comme une simple aide à la génération de code. Tant que la compatibilité des modèles est assurée dans toutes les bases de données auxquelles vous vous connectez, tout devrait fonctionner.

9
Anders Abel

J'ai regardé cette vidéo de Rowan Miller à partir de mars 2014: Migrations - Under the Hood

Dans la vidéo, Rowan explique que la commande Add-Migration effectue plusieurs étapes, parmi lesquelles un composant appelé EdmModelDiffer. Le EdmModelDiffer compare le modèle actuel à un modèle précédent de la dernière migration (intégré dans le fichier resx de la migration précédente) et calcule ensuite les modifications requises dans la base de données.

Donc, le composant EdmModelDiffer a besoin de la connexion à la base de données.

Les étapes décrites dans la vidéo sont les suivantes:

  1. Construire le modèle actuel à partir du code
  2. Récupère le modèle précédent de la dernière migration (stocké sous forme d'instantané dans un fichier resx)
  3. Calculer les modifications requises dans la base de données (effectuées par la variable EdmModelDiffer)
  4. Généré le nouveau fichier de migration

Théoriquement, on pourrait présumer qu'il suffirait de comparer le modèle actuel au modèle de la dernière migration pour générer la nouvelle migration ..__ Mais, entre-temps, d'autres personnes auraient également pu modifier la base de données. C’est probablement pour cette raison qu’il existe également une vérification de la base de données . Sans cela, le fichier de migration résultant n'aurait pas besoin d'être correct.


Regardez également la deuxième vidéo intitulée Migrations - Team Environments

0
Martin

OP a écrit:

Mais Add-Migration ne dispose-t-il pas de tout ce dont il a besoin depuis DbContext et la configuration?

Non - comme d'autres l'ont mentionné ici, la partie concepteur du code d'une migration manuelle (créée par add-migration) contient un instantané du schéma de votre base de données.

Cela dit, le fait que vous utilisiez une chaîne de connexion, etc. est très étrange. EF l’implique normalement depuis vos classes DbContext et Web.Config. Dans un projet où j'ai une seule base de données et un seul DbContext, je crée une classe de configuration et ajoute une migration manuelle avec:

add-migration

Je n'ai pas besoin de passer d'autres arguments en ligne de commande. C'est dans EF 4.3.1 - vous utilisiez peut-être un CTP ou une version plus ancienne, ou avez-vous simplement mal compris la documentation?

Si j'ai plusieurs DB ou DbContexts, j'ai plusieurs classes de configuration et j'utilise par exemple:

add-migration -conf Log

Qui utilise ma classe de configuration et la chaîne de connexion associée dans Web.config pour ajouter une migration manuelle à cette base de données/DbContext.

Voici un exemple de code plus long d'un DbContext simple destiné à stocker des journaux (distinct de la base de données principale):

namespace MyProj.Models.Log
{
    public class LogDb : DbContext
    {
        public DbSet<LogLine> LogLines { get; set; }
        public DbSet<LogTag> LogTags { get; set; }


        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
        }
    }

    public LogDb()
#if DEPLOYDB
         : base("LogDeploy")
#else
         : base()
#endif
     {
     }
}

namespace MyProj.Migrations
{
    internal sealed class Log : DbMigrationsConfiguration<LogDb>
    {
        public Log()
        {
            AutomaticMigrationsEnabled = true;
        }
    }
}

Dans Web.Config:

<add name="LogDb" connectionString="Initial Catalog=Log;Data Source=.\SqlExpress;Integrated Security=SSPI;MultipleActiveResultSets=true" providerName="System.Data.SqlClient" />
<add name="LogDeploy" connectionString="Initial Catalog=Log;Data Source=00.00.000.00,12345;User ID=sql;Password=xxx;Network Library=DBMSSOCN" providerName="System.Data.SqlClient" />

Donc, dans cet exemple, j'ai plusieurs bases de données, plusieurs DbContexts. LogDb utilise une chaîne de connexion différente dans Web.Config selon que "DBDEPLOY" est défini ou non lors de la compilation. Si c'est le cas, il utilise "LogDeploy". Sinon, il utilise la valeur par défaut - la chaîne de connexion portant le même nom que la classe, "LogDb". Cela me permet de déployer facilement les modifications de base de données sur un serveur à partir de ma machine locale, en changeant ma configuration de projet, en ouvrant un port sur la machine db SQL et en exécutant:

> update-database -conf Log

dans la console du gestionnaire de packages.

0
Chris Moschini