Code First to a New Database (Création d’une nouvelle base de données avec Code First)

Cette vidéo et ce guide pas à pas fournissent une introduction au développement Code First ciblant une nouvelle base de données. Ce scénario inclut le ciblage d’une base de données qui n’existe pas et qui sera créée par Code First, ou une base de données vide à laquelle Code First ajoute de nouvelles tables. Code First vous permet de définir votre modèle à l’aide de classes C# ou VB.Net. Vous pouvez éventuellement effectuer une configuration supplémentaire à l’aide d’attributs sur vos classes et propriétés, ou à l’aide d’une API Fluent.

Regardez la vidéo

Cette vidéo fournit une introduction au développement Code First qui cible une nouvelle base de données. Ce scénario inclut le ciblage d’une base de données qui n’existe pas et qui sera créée par Code First, ou une base de données vide à laquelle Code First ajoute de nouvelles tables. Code First vous permet de définir votre modèle à l’aide de classes C# ou VB.Net. Vous pouvez éventuellement effectuer une configuration supplémentaire à l’aide d’attributs sur vos classes et propriétés, ou à l’aide d’une API Fluent.

Présentée par : Rowan Miller

Vidéo : WMV | MP4 | WMV (ZIP)

Conditions préalables

Vous devez au moins avoir Visual Studio 2010 ou Visual Studio 2012 installés pour compléter ce guide.

Si vous utilisez Visual Studio 2010, vous devez également avoir NuGet installé.

1. Création de l’application

Pour simplifier les choses, nous allons générer une application console de base qui utilise Code First pour effectuer l’accès aux données.

  • Ouvrez Visual Studio.
  • Fichier -> Nouveau -> Projet
  • Dans le menu de gauche, sélectionnez Windows puis Application console
  • Entrez CodeFirstNewDatabaseSample comme nom
  • Sélectionnez OK.

2. Création du modèle

Définissons un modèle très simple à l’aide de classes. Ici, nous les définissons simplement dans le fichier Program.cs. Toutefois, lors d’une application réelle, vous fractionnez vos classes en fichiers distincts et potentiellement en un projet distinct.

Sous la définition de classe Program dans Program.cs, ajoutez les deux classes suivantes.

public class Blog
{
    public int BlogId { get; set; }
    public string Name { get; set; }

    public virtual List<Post> Posts { get; set; }
}

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

    public int BlogId { get; set; }
    public virtual Blog Blog { get; set; }
}

Vous remarquerez que nous rendons les deux propriétés de navigation (Blog.Posts et Post.Blog) virtuelles. Cela active la fonctionnalité de chargement différé d’Entity Framework. Le chargement différé signifie que le contenu de ces propriétés est automatiquement chargé à partir de la base de données lorsque vous essayez d’y accéder.

3. Création d’un contexte

Il faut maintenant créer un contexte dérivé. Celui-ci représente une session avec la base de données, ce qui nous permet d’interroger et d’enregistrer des données. Nous définissons un contexte qui dérive de System.Data.Entity.DbContext et expose un DbSet<TEntity> typé pour chaque classe dans notre modèle.

Nous commençons maintenant à utiliser des types à partir du Entity Framework. Nous devons donc ajouter le package NuGet d’EntityFramework.

  • Projet -> Gérer les packages NuGet... Remarque : si vous n’avez pas l’option Gérer les packages NuGet..., vous devez installer la dernière version de NuGet
  • Sélectionnez l’onglet En ligne
  • Sélectionnez le package EntityFramework
  • Cliquez sur Install.

Ajoutez une instruction using pour System.Data.Entity en haut de Program.cs.

using System.Data.Entity;

En dessous de la classe Post dans Program.cs, ajoutez le contexte dérivé suivant.

public class BloggingContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }
    public DbSet<Post> Posts { get; set; }
}

Voici une liste complète de ce que Program.cs doit désormais contenir.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data.Entity;

namespace CodeFirstNewDatabaseSample
{
    class Program
    {
        static void Main(string[] args)
        {
        }
    }

    public class Blog
    {
        public int BlogId { get; set; }
        public string Name { get; set; }

        public virtual List<Post> Posts { get; set; }
    }

    public class Post
    {
        public int PostId { get; set; }
        public string Title { get; set; }
        public string Content { get; set; }

        public int BlogId { get; set; }
        public virtual Blog Blog { get; set; }
    }

    public class BloggingContext : DbContext
    {
        public DbSet<Blog> Blogs { get; set; }
        public DbSet<Post> Posts { get; set; }
    }
}

Il s’agit de tout le code dont nous avons besoin pour commencer à stocker et à récupérer des données. Évidemment, beaucoup de choses se passent en arrière-plan, mais voyons-le d’abord à l’œuvre avant d’examiner ces éléments.

4. Lecture et écriture de données

Implémentez la méthode Main dans Program.cs, comme indiqué ci-dessous. Ce code crée une instance de notre contexte, puis l’utilise pour insérer un nouveau Blog. Il utilise ensuite une requête LINQ pour récupérer tous les Blogs de la base de données classées par titre en ordre alphabétique.

class Program
{
    static void Main(string[] args)
    {
        using (var db = new BloggingContext())
        {
            // Create and save a new Blog
            Console.Write("Enter a name for a new Blog: ");
            var name = Console.ReadLine();

            var blog = new Blog { Name = name };
            db.Blogs.Add(blog);
            db.SaveChanges();

            // Display all Blogs from the database
            var query = from b in db.Blogs
                        orderby b.Name
                        select b;

            Console.WriteLine("All blogs in the database:");
            foreach (var item in query)
            {
                Console.WriteLine(item.Name);
            }

            Console.WriteLine("Press any key to exit...");
            Console.ReadKey();
        }
    }
}

Vous pouvez maintenant exécuter l’application et la tester.

Enter a name for a new Blog: ADO.NET Blog
All blogs in the database:
ADO.NET Blog
Press any key to exit...

Où sont mes données ?

Par convention, DbContext vous a créé une base de données.

  • Si une instance SQL Express locale est disponible (installée par défaut avec Visual Studio 2010), alors Code First a créé la base de données sur celle-ci
  • Si SQL Express n’est pas disponible, alors Code First essaie d’utiliser LocalDB (installé par défaut avec Visual Studio 2012)
  • La base de données est nommée après le nom complet du contexte dérivé, ce qui est CodeFirstNewDatabaseSample.BloggingContext dans notre cas

Il s’agit simplement de conventions par défaut et il existe différentes façons de modifier la base de données utilisée par Code First. Trouvez plus d’informations dans la rubrique Comment DbContext découvre le modèle et la connexion de base de données. Vous pouvez vous connecter à cette base de données à l’aide de l’Explorateur de serveurs dans Visual Studio

  • Affichage -> Explorateur de serveurs

  • Cliquez avec le bouton droit sur Connexions de données et sélectionnez Ajouter une connexion…

  • Si vous ne vous êtes pas déjà connecté à une base de données à partir de l’Explorateur de serveurs, vous devez sélectionner Microsoft SQL Server comme source de données

    Select Data Source

  • Connectez-vous à LocalDB ou SQL Express, selon la version qui est installée

Nous pouvons maintenant inspecter le schéma créé par Code First.

Schema Initial

DbContext a élaboré les classes à inclure dans le modèle en examinant les propriétés DbSet que nous avons définies. Il utilise ensuite le jeu par défaut des conventions Code First pour déterminer les noms de table et de colonne, déterminer les types de données, rechercher des clés primaires, etc. Plus loin dans ce guide, nous allons examiner comment vous pouvez remplacer ces conventions.

5. Gestion des modifications de modèle

Maintenant, c’est le moment d’apporter des modifications à notre modèle. Lorsque nous effectuons ces modifications, nous devons également mettre à jour le schéma de base de données. Pour ce faire, nous allons utiliser une fonctionnalité appelée Code First Migrations, ou Migrations pour faire bref.

Les migrations nous permettent d’avoir un ensemble ordonné d’étapes qui décrivent comment mettre à niveau (et passer à une version antérieure) notre schéma de base de données. Chacune de ces étapes, appelées migration, contient du code qui décrit les modifications à appliquer. 

La première étape consiste à activer Code First Migrations pour notre BloggingContext.

  • Outils -> Gestionnaire de package de bibliothèque -> Console du Gestionnaire de package

  • Exécutez la commande Enable-Migrations dans la Console du Gestionnaire de Package

  • Un nouveau dossier Migrations a été ajouté à notre projet. Il contient deux éléments :

    • Configuration.cs : ce fichier contient les paramètres utilisés par Migrations pour migrer BloggingContext. Nous n’avons pas besoin de modifier quoi que ce soit pour ce guide, mais voici où vous pouvez spécifier des données initiales, inscrire des fournisseurs pour d’autres bases de données, modifier l’espace de noms dans lequel les migrations sont générées, etc.
    • <timestamp>_InitialCreate.cs : si c’est votre première migration, il représente les modifications qui ont déjà été appliquées à la base de données pour qu’elle passe d’une base de données vide à une base de données qui inclut les tables Blogs et Posts. Bien que nous laissons Code First créer automatiquement ces tables à notre place, elles ont été converties en migration maintenant que nous avons choisi d’utiliser Migrations. Code First a également enregistré dans notre base de données locale le fait que cette migration a déjà été appliquée. Le timestamp sur le nom de fichier est utilisé à des fins de tri.

    Nous allons maintenant modifier notre modèle en ajoutant une propriété URL à la classe Blog :

public class Blog
{
    public int BlogId { get; set; }
    public string Name { get; set; }
    public string Url { get; set; }

    public virtual List<Post> Posts { get; set; }
}
  • Exécutez la commande Add-Migration AddUrl dans la console du Gestionnaire de package. La commande Add-Migration recherche les modifications depuis votre dernière migration et génère automatiquement une nouvelle migration avec les modifications trouvées. Nous pouvons donner un nom aux migrations—dans ce cas, nous appelons la migration « AddUrl ». Le code généré automatiquement indique que nous devons ajouter à la table dbo.Blogs une colonne URL qui peut contenir des données de chaîne. Si nécessaire, nous pouvons modifier le code généré automatiquement, mais cela n’est pas obligatoire dans ce cas.
namespace CodeFirstNewDatabaseSample.Migrations
{
    using System;
    using System.Data.Entity.Migrations;

    public partial class AddUrl : DbMigration
    {
        public override void Up()
        {
            AddColumn("dbo.Blogs", "Url", c => c.String());
        }

        public override void Down()
        {
            DropColumn("dbo.Blogs", "Url");
        }
    }
}
  • Exécutez la commande Update-Database dans la console du Gestionnaire de package. Cette commande applique à la base de données toutes les migrations en attente. Notre migration InitialCreate a déjà été appliquée. Les migrations s’appliquent donc simplement à notre nouvelle migration AddUrl. Conseil : vous pouvez utiliser le commutateur –Verbose lorsque vous appelez Update-Database pour afficher le SQL en cours d’exécution sur la base de données.

La nouvelle colonne URL est désormais ajoutée à la table Blogs dans la base de données :

Schema With Url

6. Annotations de données

Jusqu’à présent, nous avons simplement permis à EF de découvrir le modèle à l’aide de ses conventions par défaut. Il y a cependant des moments où nos classes ne respectent pas les conventions et où nous devons être en mesure d’effectuer une configuration supplémentaire. Il y a deux options pour ce faire. Nous allons examiner les annotations de données dans cette section, puis l’API Fluent dans la section suivante.

  • Ajoutons une classe User à notre modèle
public class User
{
    public string Username { get; set; }
    public string DisplayName { get; set; }
}
  • Nous devons également ajouter un jeu à notre contexte dérivé
public class BloggingContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }
    public DbSet<Post> Posts { get; set; }
    public DbSet<User> Users { get; set; }
}
  • Si nous essayons d’ajouter une migration, nous obtenons une erreur indiquant « L’EntityType ’User’ n’a aucune clé définie. Définissez la clé pour cet EntityType. », car EF n’a aucun moyen de savoir que Username doit être la clé primaire pour User.
  • Nous allons maintenant utiliser des annotations de données pour ajouter une instruction using en haut de Program.cs
using System.ComponentModel.DataAnnotations;
  • Annotez maintenant la propriété Username pour identifier qu’il s’agit de la clé primaire
public class User
{
    [Key]
    public string Username { get; set; }
    public string DisplayName { get; set; }
}
  • Utilisez la commande Add-Migration AddUser pour générer automatiquement une migration afin d’appliquer ces modifications à la base de données
  • Exécutez la commande Update-Database pour appliquer cette migration à la base de données

La nouvelle table est maintenant ajoutée à la base de données :

Schema With Users

La liste complète des annotations prises en charge par EF est la suivante :

7. API Fluent

Dans la section précédente, nous avons examiné l’utilisation des annotations de données pour compléter ou remplacer ce qui a été détecté par convention. L’autre moyen de configurer le modèle consiste à utiliser l’API Fluent Code First.

La plupart des configurations de modèle peuvent être effectuées à l’aide d’annotations de données simples. L’API Fluent est un moyen plus avancé de spécifier la configuration de modèle qui couvre tout ce que les annotations de données peuvent faire en plus d’une configuration plus avancée qui n’est pas possible avec les annotations de données. Les annotations de données et l’API Fluent peuvent être utilisées ensemble.

Pour accéder à l’API Fluent, vous écrasez la méthode OnModelCreating dans DbContext. Supposons que nous voulons renommer à display_name la colonne dans laquelle User.DisplayName est stocké.

  • Écrasez la méthode OnModelCreating sur BloggingContext avec le code suivant
public class BloggingContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }
    public DbSet<Post> Posts { get; set; }
    public DbSet<User> Users { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<User>()
            .Property(u => u.DisplayName)
            .HasColumnName("display_name");
    }
}
  • Utilisez la commande Add-Migration ChangeDisplayName pour générer automatiquement une migration afin d’appliquer ces modifications à la base de données.
  • Exécutez la commande Update-Database pour appliquer la nouvelle migration à la base de données.

La colonne DisplayName est désormais renommée display_name :

Schema With Display Name Renamed

Résumé

Dans ce guide, nous avons examiné le développement Code First avec une nouvelle base de données. Nous avons défini un modèle à l’aide de classes, puis nous avons utilisé ce modèle pour créer une base de données, ainsi que pour stocker et récupérer des données. Une fois la base de données créée, nous avons utilisé Code First Migrations pour modifier le schéma à mesure que notre modèle évolue. Nous avons également vu comment configurer un modèle à l’aide des annotations de données et de l’API Fluent.