Les migrations automatiques avec Entity Framework 5

Nous allons aborder le sujet concernant l'initialisation de la BDD avec entity framework et code first qui parfois peut s'avérer être un vrai casse tête dans certaines situations. Si l'on essaye pas de prendre un peu de temps afin de bien comprendre son mécanisme, on peu très vite s'arracher les cheveux ! (Ce qui est encore mon cas...) Je vais tenté de vous expliquer ce que j'ai pu comprendre de ce mécanisme de manière la plus claire possible.

Tout d'abord, Il faut que vous sachiez que la méthode statique à utiliser au sein de votre code pour initialiser votre base de données au lancement de votre application est la suivante : Database.SetInitializer(). Pour mettre en place une stratégie d'initialisation de la BDD, nous devrons fournir un argument à cette méthode qui doit représenter l'instance d'une des classes suivantes dont je vous propose une petite explication :

  • new CreateDatabaseIfNotExists<Context>() : C'est l'initialisation par défaut si aucune stratégie n'est mise en place explicitement, elle permet de créer une base de données uniquement si celle-ci n'existe pas.
  • new DropCreateDatabaseWhenModelChanges<Context>() : Permet de créer une BDD suivant votre model Code First (si cette dernière n'existe pas) ou de supprimer puis de recréer votre BDD selon si votre modèle change ou non.
  • new DropCreateDatabaseAlways<Context>() : Supprime votre BDD (si elle existe) et la recrée systématiquement quelque soit votre modèle.
  • new MigrateDatabaseToLatestVersion<Context, Configuration>() : Ne s'utilise pas de la même manière que les classes précédentes. Disponible depuis la version 4.3 d'EF, elle permet d'utiliser les migrations pour une transition en douceur d'un modèle à l'autre sans perte de données dans la majorité des cas. Elle sera expliquée de manière plus précise dans la partie "Les migrations" de cet article.

Context désigne ici la classe dans votre projet qui hérite de DbContext. Cette dernière est indispensable car elle va permettre la gestion de toutes vos entités au sein d'entity framework.

Si vous ne souhaitez pas utiliser une stratégie d'initialisation de la BDD, autrement dit ne rien faire du tout, vous pouvez utiliser ceci :

Database.SetInitializer<Context>(null);

En plus de ces différentes méthodes d'initialisation, vous pouvez créer la votre avec l'implémentation de l'interface IDatabaseInitializer (cette façon de faire ne sera pas approfondie dans cet article, mais il est bon de savoir que c'est possible)

Pour initialiser notre BDD au démarrage d'une application, nous devrons par exemple, écrire notre méthode Database.SetInitializer dans la méthode Main() d'une application console ou encore dans la méthode Application_Start() (fichier Global.asax) d'une application ASP .NET MVC.

Les migrations avec Entity Framework et Code First

Alors attention accrochez vous, c'est partie pour l'explication du fonctionnement des migrations avec Code First ! Pour faire fonctionner les migrations au sein d'un projet ASP .NET MVC, vous devez activer la console du package NuGet et exécuter une commande qui activera la gestion des migrations. Pour l'accès à la console NuGet, vous devez aller dans "outils", "gestionnaire de package de bibliothèques" et "console du gestionnaire de package"

NuGet

Ensuite vous devrez exécuter la commande suivante :

enable-migrations

Cette commande aura pour effet de créer une table dbo.__migrationhistory et un dossier nommé Migrations contenant un fichier Configuration.cs à la racine de votre projet contenant ceci :

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

Ici, la propriété AutomaticMigrationsEnabled est à false par defaut, ce qui n'est pas très intéressant puisque nous souhaiterions que notre base de données s'adapte automatique à notre modèle avec le moins d’effort possible. Nous allons alors changer sa valeur à true. Pour le faire de manière automatique, nous aurions pu, à l'activation des migrations, ajouter le paramètre -EnableAutomaticMigrations, ce qui nous donne :

enable-migrations -EnableAutomaticMigrations

Une deuxième propriété intéressante est la suivante :

AutomaticMigrationDataLossAllowed = true

Elle permet d'effectuer une migration automatique sans avertissement sur une éventuelle perte de données ! Exemple : J'ai un champ de type string que je décide de changer en type int, toutes ses valeurs seront logiquement perdues. A utiliser alors avec précaution et à éviter sur un environnement de production.

Les migrations automatiques sont une fonctionnalité indispensable pour faire évoluer notre BDD en même temps que notre modèle de manière parallèle, sans avoir à supprimer et recréer une BDD systématiquement. Cependant, il peut arriver parfois de ne pas avoir recours à la migration automatique afin d'intervenir de manière plus précise sur certaines erreurs que pourrait relever Entity Framework. C'est ce que nous allons voir un peu plus loin dans cette article à la rubrique "Ajouter un fichier de migration"

A chaque mise à jour de la BDD grâce aux migrations, une insertion dans la table historique des migrations est effectuée. Cette table permet donc de tracer les migrations effectuées et donc d'avoir connaissance de la structure actuelle de la BDD. Lors d'une tentative de migration, si la signature spécifique au modèle actuel est différent de la signature dans la table historique, une migration est opérée.

Ajouter un fichier de migration

Pour effectuer une migration manuelle, vous devez ajouter ce que l'on appel un fichier de migrations. La commande à taper dans la console est la suivante :

add-migration newMigration // newMigration est le nom de votre fichier

Vous retrouverez un fichier qui se nomme avec la date de création et le nom que vous lui avez donné, dans le dossier Migrations. Ce fichier contient deux méthodes : Up et Down. Ces dernières contiennent des instructions d'actions sur la BDD qui vont s’exécuter afin de se rendre conforme vis à vis de votre modèle. Faite le test ! Modifier votre model et ajoutez-y un fichier de migration pour observer ces instructions. Pour prendre en compte vos modifications manuelles, ne pas oublié de lancer "update-database" et la migration sera effective selon le fichier de migration le plus récent.