c# - type - utilisez migrations code first pour mettre à jour la base de données




Migrations dans Entity Framework dans un environnement collaboratif (6)

Option 1: Ajouter une migration "fusion" vide

  1. Assurez-vous que toutes les modifications de modèle en attente dans votre base de code locale ont été écrites dans une migration. Cette étape garantit que vous ne manquerez aucun changement légitime au moment de générer la migration vide.
  2. Synchroniser avec le contrôle de la source.
  3. Exécutez Update-Database pour appliquer les nouvelles migrations que les autres développeurs ont enregistrées. ** Remarque: **** si vous n'obtenez aucun avertissement de la commande Update-Database, aucune nouvelle migration n'a été effectuée par d'autres développeurs. pas besoin d'effectuer une nouvelle fusion.
  4. Exécutez Add-Migration -IgnoreChanges (par exemple, Add-Migration Merge -IgnoreChanges). Cela génère une migration avec toutes les métadonnées (y compris un instantané du modèle actuel) mais ignore les modifications détectées lors de la comparaison du modèle actuel à l'instantané lors des dernières migrations (ce qui signifie que vous obtenez une méthode Haut et Bas).
  5. Continuez à développer, ou soumettez au contrôle de source (après avoir exécuté vos tests unitaires bien sûr).

Option 2: mise à jour de l'instantané du modèle dans la dernière migration

  1. Assurez-vous que toutes les modifications de modèle en attente dans votre base de code locale ont été écrites dans une migration. Cette étape garantit que vous ne manquerez aucun changement légitime au moment de générer la migration vide.
  2. Synchroniser avec le contrôle de la source.
  3. Exécutez Update-Database pour appliquer les nouvelles migrations que les autres développeurs ont enregistrées. ** Remarque: **** si vous n'obtenez aucun avertissement de la commande Update-Database, aucune nouvelle migration n'a été effectuée par d'autres développeurs. pas besoin d'effectuer une nouvelle fusion.
  4. Exécutez Update-Database -TargetMigration (dans l'exemple que nous avons suivi, Update-Database -TargetMigration AddRating). Cela permet à la base de données de revenir à l'état de la deuxième dernière migration, c'est-à-dire de «désappliquer» la dernière migration de la base de données. ** Remarque: **** Cette étape est nécessaire pour sécuriser la modification des métadonnées de la migration, car les métadonnées sont également stockées dans le tableau __MigrationsHistoryTable de la base de données. C'est pourquoi vous ne devez utiliser cette option que si la dernière migration est uniquement dans votre base de code locale. Si la dernière migration a été appliquée à d'autres bases de données, vous devez également les annuler et réappliquer la dernière migration pour mettre à jour les métadonnées.
  5. Exécutez Add-Migration (dans l'exemple que nous avons suivi, cela ressemblerait à Add-Migration 201311062215252_AddReaders). ** Remarque: **** Vous devez inclure l'horodatage afin que les migrations sachent que vous souhaitez modifier la migration existante plutôt que d'en créer une nouvelle. Cela mettra à jour les métadonnées de la dernière migration pour correspondre au modèle actuel. Vous obtiendrez l'avertissement suivant lorsque la commande est terminée, mais c'est exactement ce que vous voulez. "Seul le code du concepteur pour la migration '201311062215252_AddReaders' a été rééchappé. Pour réexécuter la migration entière, utilisez le paramètre -Force. "
  6. Exécutez Update-Database pour réappliquer la dernière migration avec les métadonnées mises à jour.
  7. Continuez à développer, ou soumettez au contrôle de source (après avoir exécuté vos tests unitaires bien sûr).

MSDN a un bon article à ce sujet. S'il vous plaît, passez par là.

Entity Framework Code Premières migrations dans des environnements d'équipe

Nous avons plusieurs développeurs travaillant sur un projet qui utilise Entity Framework 5.0. Chaque développeur utilise sa propre base de données SQL 2012 locale pour pouvoir développer et tester sans gêner les autres.

Au début, nous avons utilisé un hybride de migrations automatiques et de migrations basées sur le code. Cela ne fonctionnait pas du tout, nous avons donc décidé de désactiver les migrations automatiques et de n'autoriser que le code. Je dois ajouter que nous avons recommencé avec une base de données propre sans _MigrationsHistory "corrompu" de toutes les migrations automatiques.

Alors maintenant, le flux de travail est:

  1. Le développeur change son datamodel
  2. Est add-migration <Name> ce que add-migration <Name> et l'applique à sa base de données avec update-database .
  3. Vérifie la modification du modèle de données et la migration dans Git.
  4. Un autre développeur tire, reçoit les modifications et les applique à sa base de données.

Jusqu'à présent, cela a bien fonctionné. Cependant, avant aujourd'hui, c'était habituellement moi qui faisait les migrations et les autres les appliquaient. Mais aujourd'hui, il y avait des migrations de trois développeurs. J'ai juste tiré ces migrations, fait une update-database qui s'est bien passée.

J'ai aussi changé mon propre datamodel, donc à la fin de la update-database il m'a averti que je n'étais toujours pas à jour et j'ai donc add-migration <my migration> . Cependant quand il a échafaudé la migration, il m'a donné les changements de toutes les migrations que j'avais déjà appliquées à la base de données. Donc: il a essayé de supprimer les colonnes qui avaient déjà été supprimées, essayé de créer une table qui existait déjà, etc.

Comment cela peut-il être? Ma supposition était que EF vérifierait simplement la table _MigrationsHistory et découvrirait quelles migrations n'étaient pas encore présentes dans la table et les appliquerait une par une en fonction de l'horodatage qui fait partie du nom. Mais apparemment non, car même si je défais mes propres changements et que j'ai un environnement propre, il se plaint encore que ma base de données n'est pas en phase avec le modèle. Mais j'ai juste tiré ces changements et les ai appliqués à ma base de données. C'est en synchronisation. Je peux voir les migrations que je viens d'appliquer dans la table _MigrationsHistory .

La seule chose que je peux penser est que j'ai ajouté une propriété à un modèle de données qui n'entraînerait pas de changement de base de données (J'ai ajouté une List<X> au modèle de données Y où X est le multiple dans la relation un-à-plusieurs. Cela ne se traduirait pas par une modification de la base de données car X avait déjà une clé étrangère à Y). Est-ce que ça pourrait être ça? Si c'est le cas, c'est vraiment fragile car il n'y a aucun moyen d'ajouter une migration pour cela car il n'y a pas de changement de base de données et je ne suis pas sûr de savoir comment résoudre ce problème non plus.

Je ne suis pas sûr de savoir comment gérer cela, car je peux bien sûr simplement modifier ce qu'il a échafaudé et supprimer tout ce qui a déjà été appliqué à ma base de données. Mais alors quoi? Je vérifie et un autre développeur obtient le même message que sa base de données n'est pas à jour, même après avoir appliqué mes nouveaux changements, échafaudé ses propres changements, obtient le même échafaudage non-sens, l'édite, le vérifie, puis le suivant le développeur l'obtient. Cela devient un cercle vicieux et similaire à ce que nous avions quand nous utilisions les migrations automatiques et je pensais que nous avions réglé cela en passant au code uniquement. Je ne peux pas faire confiance maintenant pour faire la bonne chose et c'est un cauchemar pour travailler comme ça.

Ce que j'ai également essayé est d'ajouter les migrations que j'ai tirées de mes collègues un par un avec update-database -t:201211091112102_<migrationname> mais en vain. Cela me donne toujours l'échafaudage erroné.

Alors qu'est-ce que nous avons fait de mal ici, ou est-ce que EF n'est tout simplement pas construit pour une collaboration comme celle-ci?

METTRE À JOUR

J'ai créé un cas de test reproductible, mais c'est un peu long pour simuler ce scénario multi-utilisateurs / multi-bases de données.

https://github.com/JulianR/EfMigrationsTest/

Étapes à reproduire lorsque vous avez le projet ci-dessus (ces étapes sont également présentes dans le code):

  1. add-migration Init
  2. update-database (sur la base de données 'TestDb')
  3. Modifier la chaîne de connexion pour pointer vers TestDb1
  4. base de données de mise à jour sur TestDb1
  5. Décommenter la propriété Foo sur le test de classe
  6. add-migration M1 pour ajouter la propriété Foo à TestDb1
  7. Commentez à nouveau Test.Foo
  8. Modifier la chaîne de connexion pour pointer vers TestDb2
  9. Exclure la migration M1 du projet afin qu'elle ne soit pas appliquée à TestDb2
  10. Décommenter la propriété Barre en cours Test
  11. update-database pour appliquer la migration Init à TestDb2
  12. add-migration M2 pour ajouter la propriété Bar à TestDb2
  13. Modifier à nouveau la chaîne de connexion pour pointer vers TestDb d'origine
  14. Inclure à nouveau la migration M1 dans le projet
  15. Décommenter la propriété Foo sur le test de classe
  16. Décommenter la propriété SomeInt sur le test de classe
  17. update-database
  18. migration additionnelle M3
  19. update-database, obtenez une erreur car M3 essaie d'ajouter la colonne Foo à la base de données TestDb qui a déjà été ajoutée par la migration M1.

Ce qui précède est de simuler trois utilisateurs, où l'utilisateur 1 crée sa base de données, les deux autres utilisent son initialisation pour créer leur base de données. Ensuite, l'utilisateur 2 et l'utilisateur 3 apportent chacun leur propre changement au modèle de données et l'ajoutent au contrôle de la source avec les migrations nécessaires pour appliquer les modifications. Ensuite, l'utilisateur 1 tire les changements de l'utilisateur 2 et 3 tandis que l'utilisateur 1 a également apporté lui-même une modification à la base de données. Ensuite, l'utilisateur 1 appelle update-database pour appliquer les changements des utilisateurs 2 et 3. Il échafaude alors sa propre migration qui ajoute ensuite par erreur une modification de l'utilisateur 2 ou 3 à la migration échafaudée qui provoque une erreur lors de l'application à la base de données de l'utilisateur.



Je suis d'accord avec @LavaEater. Le noyau de la question, semble-t-il, est que l'échafaudage de migration devrait être centralisé. Peut-être dans le cadre d'un processus de construction automatisé / intégré chaque fois qu'une poussée se produit? Par la suite, les migrations résultantes peuvent être retirées du serveur par les membres de l'équipe.

Cela signifie que leurs propres scripts de migration ne doivent pas être transmis au serveur.


La solution que j'ai pu trouver (au moins pour 2 utilisateurs, je n'ai pas testé pour 3) est:

  1. fusionner les migrations pour synchroniser la base de données update-meta-data run (cela devrait échouer), puis
  2. ajouter-base de données, puis
  3. supprime tout le code généré dans up() méthodes up() et down()

ceci sera toujours exécuté par la base de données de mise à jour, mais ne fera rien, juste en mettant les métadonnées à la synchronisation.


Vous devez ajouter une migration "fusion" vide qui réinitialisera l'instantané de la dernière migration dans le fichier .resx. Pour ce faire, utilisez le commutateur IgnoreChanges:

Add-Migration <migration name> -IgnoreChanges

Voir here pour une explication


Vous devez résoudre manuellement les conflits de migration, comme vous le feriez pour les conflits de code. Si vous effectuez une mise à jour et qu'il y a de nouvelles migrations, vous devez vous assurer que les métadonnées derrière la dernière migration correspondent au modèle actuel. Pour mettre à jour les métadonnées de la migration, relancez la commande Add-Migration correspondante.

Par exemple, avant l'étape 17 (Update-Database) dans votre scénario, vous devez exécuter la commande suivante

Add-Migration M2

Cela mettra à jour les métadonnées pour les synchroniser avec votre modèle actuel. Maintenant, lorsque vous essayez d'ajouter M3, il doit être vide puisque vous n'avez pas modifié d'autres modèles.





code-first-migrations