I. Introduction▲
Pendant le développement ou le cycle de vie d'une application, le développeur est très souvent confronté à des situations pouvant entrainer des modifications de son modèle objet ainsi que de sa base de données. Avec Entity Framework, cette tâche peut s'avérer assez complexe, voire frustrante pour certains.
Si vous voulez par exemple apporter une modification (ajout d'une colonne) à une table de votre base de données, si vous vous limitez à définir uniquement la nouvelle colonne dans votre modèle, lors de l'exécution de l'application vous allez obtenir un message d'erreur puisque le modèle ne correspond plus aux objets de la BD.
Il était cependant possible d'ajouter quelques lignes de code dans le fichier Global.asax, permettant lors de la modification du modèle, de détruire et recréer automatiquement la base de données lors de la prochaine exécution de l'application, avec comme conséquence directe la perte des données. Ce qui est inacceptable pour une base de données déjà en production.
Heureusement, Entity Framework 4.3 élimine ces contraintes avec la nouvelle fonctionnalité Code First Migrations, qui permet d'appliquer avec souplesse les modifications du modèle sur la base de données, en réduisant les risques de pertes de données.
II. Prérequis▲
Il est important que vous ayez des connaissances de base sur la programmation .NET, le langage C# et l'ORM Entity Framework.
Pour l'exemple qui sera décrit tout au long de cet article, nous avons utilisé Visual Web Developer 2010 Service Pack 1, ASP.NET MVC 4 Beta et Entity Framework 4.3.
III. Utilisation de Code First Migrations▲
Créez une nouvelle application ASP.NET MVC 4 " DataMigration " en utilisant le modèle Internet Application. Avec NuGet, vous allez faire une mise à jour d'Entity Framework vers la dernière version de la bibliothèque, qui ajoute les fonctionnalités de migrations des bases de données.
Vous pouvez également utiliser la console NuGet Manager pour effectuer la mise à jour d'Entity Framework ou installer celui-ci.
Pour plus de détails sur NuGet, voir le tutoriel : Présentation du gestionnaire de packages .NET NuGet.
Vous allez ajouter une nouvelle classe " Customer " dans le modèle. Le code pour cette classe est le suivant :
public
class
Customer
{
public
short
Id {
get
;
set
;
}
public
string
FirstName {
get
;
set
;
}
public
string
LastName {
get
;
set
;
}
Vous allez par la suite créer un nouveau contrôleur en utilisant Entity Framework pour les actions CRUD.
Dans les options de scaffolding, vous devez sélectionner la classe Customer. Dans la zone Data context class, vous allez utiliser " New data context…>. Renseignez le nom du Data Context " DatabaseMigrationContext ". Validez ensuite sur OK et cliquez enfin sur Ajouter.
Un fichier DataBaseMigrationContext.cs sera automatiquement ajouté à votre application.
Exécutez celle-ci afin que Code First utilise le modèle pour créer la base de données qui sera automatiquement ajoutée à votre instance SQL Server locale.
III-A. Activation de la migration▲
Supposons que vous voulez ajouter une propriété Email dans votre modèle. Vous allez pour ce faire modifier celui-ci en ajoutant cette nouvelle propriété :
public
class
Customer
{
public
short
Id {
get
;
set
;
}
public
string
FirstName {
get
;
set
;
}
public
string
LastName {
get
;
set
;
}
public
string
EMail {
get
;
set
;
}
}
Si vous exécutez votre application ainsi, vous allez obtenir le message d'erreur suivant :
Comme l'exception le signale, il est temps pour vous d'utiliser Code First Migrations pour procéder à la mise à jour de votre base de données.
La première étape est d'activer la migration pour votre Context, en utilisant la console du gestionnaire de packages (menu Outils/Gestionnaire de package/Package Manager Console de Visual Studio). Vous allez exécuter la commande suivante : Enable-Migrations.
L'activation de la migration crée un nouveau dossier Migrations dans votre application contenant un fichier Configurations.cs, permettant de définir le comportement de la migration pour le DbContext utilisé.
namespace
DatabaseMigration.
Migrations
{
using
System;
using
System.
Data.
Entity;
using
System.
Data.
Entity.
Migrations;
using
System.
Linq;
internal
sealed
class
Configuration :
DbMigrationsConfiguration<
DatabaseMigration.
DatabaseMigrationContext>
{
public
Configuration
(
)
{
AutomaticMigrationsEnabled =
false
;
}
protected
override
void
Seed
(
DatabaseMigration.
DatabaseMigrationContext context)
{
}
}
}
Si vous avez défini plusieurs "DbContext " dans votre application, il suffira de modifier DbMigrationsConfiguration(T), en remplaçant T par le nom du DbContext que vous voulez utiliser.
Deux modes peuvent être utilisés pour mettre à jour la base de données en utilisant Database Migrations. Vous pouvez décider d'utiliser la migration basée sur le code ou la migration automatique. Il suffit de faire passer AutomaticMigrationsEnabled à False pour le premier cas, et True pour le second.
Un autre fichier est également créé. Ce fichier contient une procédure Up() qui contient des instructions pour créer la table avec la définition initiale de celle-ci, et une autre procédure Down() pour supprimer la table.
Ce fichier pourra être utilisé pour rétablir l'état original de la base de données.
public
partial
class
InitialCreate :
DbMigration
{
public
override
void
Up
(
)
{
CreateTable
(
"Customers"
,
c =>
new
{
Id =
c.
Short
(
nullable:
false
,
identity:
true
),
FirstName =
c.
String
(
),
LastName =
c.
String
(
),
}
)
.
PrimaryKey
(
t =>
t.
Id);
}
public
override
void
Down
(
)
{
DropTable
(
"Customers"
);
}
}
Il est important de savoir comment fonctionnent les procédures Up() et Down() qui sont générées automatiquement, et à quoi correspond l'action effectuée par chacune d'elles (mise à jour ou annulation d'une mise à jour). La procédure Up() contient les lignes de code permettant de faire une mise à jour de la base de données (ajout d'une colonne, ajout d'une table, modification d'une colonne, etc.). La procédure Down() contient les lignes de code permettant de revenir en arrière pour une mise à jour dont le code est défini dans la procédure Up() (supprimer la colonne créée, supprimer la table créée, etc.).
IV. Utilisation de la migration automatique▲
Par défaut, la propriété AutomaticMigrationsEnabled est définie à False. Pour utiliser la migration automatique, vous devez affecter la valeur True à cette propriété.
Il également possible de définir cette propriété à True lors de l'activation de la migration. Pour cela, vous devez ajouter le paramètre EnableAutomaticMigrations à la commande permettant d'activer la migration :
Enable-
Migrations -
EnableAutomaticMigrations
Pour appliquer la modification que vous avez apportée à la classe Customer à votre base de données, vous allez utiliser la commande 'Update-Database' dans la console du gestionnaire de packages NuGet.
Vous pouvez observer les modifications qui ont été apportées à la base de données dans l'explorateur de serveur au sein de SQL Server Management Studio :
Passons à un second exemple. Vous souhaitez ajouter une nouvelle table Product à votre base de données.
Pour cela, vous allez dans un premier temps ajouter une nouvelle classe Product dans le dossier modèle ayant la définition suivante :
public
class
Product
{
public
short
Id {
get
;
set
;
}
public
string
Name {
get
;
set
;
}
}
N'oubliez surtout pas de référencer la classe entité Product que vous venez de créer dans votre DbContext.
public
DbSet<
Product>
Products {
get
;
set
;
}
Vous pouvez maintenant procéder à la création de la table "Products" en utilisant la commande " Update-Database ", à la différence que vous allez ajouter le paramètre " -Verbose " afin que la commande SQL utilisée soit affichée dans la console NuGet.
Un petit coup d'œil sur la base de données et vous allez vous rendre compte que la table Products a été ajoutée à celle-ci.
IV-A. Configuration de la migration automatique▲
Jusqu'ici, vous vous rendez compte que vous appliquez vous-même les changements apportés au modèle à la base de données en utilisant la commande 'Update-Database'. En principe, lors de l'utilisation de la migration automatique, Entity Framework Code First doit être capable de détecter automatiquement les changements qui ont été apportés au modèle et les appliquer à la base de données.
Pour cela, il suffit d'ajouter la procédure OnModelCreating à votre DbContext (DataBaseMigrationContext.cs) :
protected
override
void
OnModelCreating
(
DbModelBuilder modelBuilder)
{
Database.
SetInitializer
(
new
MigrateDatabaseToLatestVersion<
DatabaseMigrationContext,
Configuration>(
));
}
Vous devez également modifier le fichier Configuration.cs pour prendre en compte les migrations pouvant entrainer des pertes de données, en ajoutant la propriété AutomaticMigrationDataLossAllowed :
public
Configuration
(
)
{
AutomaticMigrationsEnabled =
true
;
AutomaticMigrationDataLossAllowed =
true
;
}
Ainsi, toute modification (nouvelle entité, ajout d'une propriété, etc.) du modèle sera automatiquement appliquée à la base de données lors de l'exécution de votre application.
IV-B. Inconvénients de la migration automatique▲
La migration automatique permet d'apporter assez rapidement et simplement des mises à jour à une base de données en utilisant Entity Framework Code First. Cette option, bien que très pratique, présente cependant quelques inconvénients et il n'est de ce fait pas conseillé d'utiliser ce mode pour une base de données critique ou en environnement de production.
Néanmoins, vous pouvez limiter ces risques en environnement de production en désactivant l'autorisation des mises à jour pouvant entrainer des pertes de données.
AutomaticMigrationDataLossAllowed =
false
;
V. Migration basée sur le code▲
La migration basée sur le code est un mode qui offre beaucoup plus de possibilités au développeur pour les mises à jour de la base de données, ainsi qu'une plus grande visibilité sur les opérations qui sont effectuées sur sa BD.
Ce mode utilise des fichiers de code générés par Entity Framework qui contiennent des instructions LinQ et SQL des modifications qui seront apportées à la base de données à partir des nouvelles définitions du modèle.
V-A. Génération des fichiers de migrations▲
Après avoir activé la migration, vous devez utiliser la commande Add-Migration suivie du nom de la migration pour générer le fichier de code des modifications qui doivent être apportées à la base de données.
Ajoutez par exemple un nouvel attribut Rating à la classe Product.
public
class
Product
{
public
short
Id {
get
;
set
;
}
public
string
Name {
get
;
set
;
}
public
int
Rating {
get
;
set
;
}
}
Exécutez par la suite la commande Add-Migration AddColumn dans la console NuGet. Le paramètre AddColumn représente le nom de la migration.
Un nouveau fichier AddColumn.cs sera automatiquement ajouté au dossier Migrations, avec un préfixe timestamp permettant à Entity Framework de savoir quels fichiers doivent être exécutés, et dans quel ordre :
Ce fichier contient par défaut le code suivant :
namespace
DatabaseMigration.
Migrations
{
using
System.
Data.
Entity.
Migrations;
public
partial
class
AddColumn :
DbMigration
{
public
override
void
Up
(
)
{
AddColumn
(
"Products"
,
"Rating"
,
c =>
c.
Int
(
nullable:
false
));
}
public
override
void
Down
(
)
{
DropColumn
(
"Products"
,
"Rating"
);
}
}
}
Vous pouvez apporter des modifications à ce fichier en ajoutant ou en supprimant des colonnes, ou en y insérant même des instructions SQL.
public
override
void
Up
(
)
{
AddColumn
(
"Products"
,
"Description"
,
c =>
c.
String
(
));
Sql
(
"UPDATE Products SET Description = LEFT(Content, 100) WHERE Description IS NULL"
);
}
Lorsque tout est OK, vous pouvez utiliser la commande Update-Database pour appliquer la migration sur votre base de données.
V-B. Exécuter un fichier de migration spécifique▲
Pour exécuter un fichier de migration spécifique, vous pouvez utiliser la commande 'Update-Database -TargetMigration:"NomDeLaMigration"'
PM>
Update-
Database -
TargetMigration:
"AddColumn"
Si la migration a déjà été appliquée, la méthode Down() sera exécutée dans ce cas pour annuler les modifications qui ont été apportées à la base de données.
Pour revenir à un état antérieur, vous pouvez également utiliser la commande :
PM >
Update-
Database -
TargetMigration:
$InitialDatabase
VI. Utilité de la table _MigrationHistory dans ma base de données▲
En observant les objets de votre base de données, vous vous rendez compte qu'une table système _MigrationHistory a été ajoutée à la BD.
La table _MigrationHistory est créée pour stocker les métadonnées sur les migrations qui ont été appliquées à la base de données. Cette table est créée lorsque Entity Framework Code First procède à la création de la base de données ou lorsque les migrations sont activées.
Elle sera utilisée par Entity Framework Code First pour connaitre l'état actuel de la migration qui a été appliquée à la base de données.
Cette table peut également s'avérer utile pour savoir les modifications qui ont été apportées à votre base de données.
VII. Conclusion▲
Au travers de cet article, vous avez découvert une des nouveautés les plus intéressantes d'Entity Framework 4.3. Désormais, les modifications de votre modèle pourront être aisément appliquées à votre base de données avec le moins d'effort possible.
VIII. Remerciements▲
Je tiens à remercier tomlev et ClaudeLELOUP pour leurs relectures et corrections.