Pourquoi L'étape Add-Migration de fe de Entity Framework nécessite-t-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 First). Afin d'échafauder un nouveau changement, j'ai utiliser une commande comme ceci:
Add-Migration MyMigration
-ConnectionString "Data Source=.;Initial Catalog=mydb;"
-ConnectionProviderName "System.Data.SqlClient"
-StartUpProjectName MyWebsite
-ProjectName MyEF.Migrations
pourquoi Add-Migration nécessite-t-elle des données de chaîne de connexion? Update-Database
en a besoin, c'est logique. Mais Add-Migration n'a-t-elle pas tout ce dont elle a besoin à partir du DbContext et de la Configuration?
ce n'est pas une simple merveille, c'est très confus de lui donner une base de données, parce que nous avons une chose "multi-location" où la base de données désirée est flexible et peut changer d'une requête à l'autre, encore moins au moment de la compilation statique. Donc si Add-Migration
utilise cette base de données pour quelque chose, nous avons un problème.
mise à jour: nous avons abandonné les Migrations EF et nous utilisons Fluent Migrator à la place, et nous sommes heureux. C'est beaucoup, beaucoup plus rapide, même en comptant le fait que nous devons écrire certaines choses deux fois (une fois pour l'objet EF et une fois pour la Migration), et il n'a pas les problèmes discutés dans cette question.
4 réponses
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 étudier les migrations en cours et aussi pour sélectionner le modèle précédent afin de trouver ce qui a changé - c'est particulièrement important si vous ajoutez la migration explicite dans la solution où les migrations automatiques sont activées.
j'ai été curieux en lisant votre question, donc j'ai lancé un profileur de Serveur Sql pour avoir un regard sur ce qui se passe quand add-migration est lancé. Il se connecte en effet à la base de données et accède à la base de données pour vérifier la table __MigrationHistory
.
ceci est également montré par le message d'erreur produit lorsque vous essayez de créer une deuxième migration basée sur le code sans exécuter la première:
impossible de générer une migration explicite suivant les migrations explicites sont en attente: [201205291928386_foo]. Appliquer le en attendant des migrations explicites avant de tenter de générer un nouveau explicite de la migration.
je pense que le moteur migrations utilise le modèle sérialisé de la base de données pour calculer quelles étapes de migration devraient être incluses dans la nouvelle migration.
pour autant que je sache, la base de données n'est utilisée que comme helper pour la génération de code. Aussi longtemps que tous les diverses 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 votre.
Modifier
comme le souligne @Ladislav Mrnka, une vérification avec la base de données est requise si le mélange est basé sur le code et les migrations automatiques. Lorsque vous planifiez 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 de les changements à 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 - puisque les migrations automatiques peuvent être activées.
si vous exécutez avec seulement des migrations basées sur le code (qui je pense est la seule option pour garder le contrôle), alors cette base de données peut être considérée comme juste une aide de génération de code. Tant que la compatibilité du modèle est assurée dans toutes les bases de données auxquelles vous vous connectez, tout devrait fonctionner.
OP a écrit:
mais N'ajoute pas-la Migration a tout ce dont elle a besoin à partir du DbContext et la Configuration?
non - comme d'autres l'ont mentionné ici la partie concepteur du code pour une Migration manuelle (ce qui est créé par add-migration
) contient un instantané de votre schéma de base de données.
cela dit, le fait que vous utilisiez une chaîne de connexion etc est très étrange. L'EF implique normalement qu'il provient de votre DbContext class (es) 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 à passer d'autres arguments en ligne de commande. C'est dans EF 4.3.1 - peut-être utilisiez-vous une version CTP ou une version plus ancienne, ou avez-vous mal compris les docs?
si j'ai plusieurs DBS ou DbContexts, alors 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 correspondante dans Web.config pour ajouter une migration manuelle pour cette base de données/DbContext.
voici un exemple de code plus long d'un DbContext simple destiné à stocker les logs (séparé du db principal):
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. La LogDb utilise une chaîne de connexion dans le Web.Config basé sur le fait que" DBDEPLOY "est défini au moment de la compilation; si c'est le cas, il utilise "LogDeploy"."Si non, il utilise la valeur par défaut - la chaîne de connexion avec le même nom que la classe, "LogDb."Cela me permet de déployer facilement des modifications DB sur un serveur depuis ma machine locale, en changeant la Configuration de mon projet, en ouvrant un port sur la machine SQL db, et en exécutant:
> update-database -conf Log
dans la Console du Gestionnaire de paquets.
j'ai regardé cette vidéo de Rowan Miller de mars 2014: Migrations-sous le capot 151980920"
dans la vidéo Rowan explique que la commande Add-Migration
exécute plusieurs étapes qui comprennent un composant appelé EdmModelDiffer
.
Le EdmModelDiffer
compare le modèle actuel avec un modèle précédent de la dernière migration (qui est intégré dans le fichier resx de la migration précédente) et calcule ensuite les changements requis à la base de données.
ainsi le composant EdmModelDiffer
nécessite la connexion à la base de données.
les étapes décrites dans la vidéo sont:
- construire le modèle actuel à partir du code
- Obtenir le modèle précédent de la dernière migration (stockés en tant qu'instantané dans le fichier resx)
- calculer les changements requis à la base de données (fait par le
EdmModelDiffer
) - a 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 pourraient avoir effectué des modifications dans la base de données. C'est probablement la raison pour laquelle il y a aussi une vérification dans la base de données. Sans cela, le fichier de migration n'aurait pas besoin d'être correct.
Jetez également un coup d'oeil à la deuxième vidéo appelé Migrations - environnements D'équipe