Créer la couche d’accès aux données

par Erik Reitan

Cette série de tutoriels vous apprend les principes de base de la création d’une application ASP.NET Web Forms à l’aide de ASP.NET 4.5 et Microsoft Visual Studio Express 2013 pour le web. Un projet Visual Studio 2013 avec du code source C# est disponible pour accompagner cette série de tutoriels.

Ce tutoriel explique comment créer, accéder et examiner des données à partir d’une base de données à l’aide de ASP.NET Web Forms et d’Entity Framework Code First. Ce tutoriel s’appuie sur le tutoriel précédent « Créer le projet » et fait partie de la série de tutoriels Wingtip Toy Store. Une fois ce tutoriel terminé, vous avez créé un groupe de classes d’accès aux données qui se trouvent dans le dossier Modèles du projet.

Ce que vous allez apprendre :

  • Comment créer les modèles de données.
  • Comment initialiser et amorcer la base de données.
  • Comment mettre à jour et configurer l’application pour prendre en charge la base de données.

Voici les fonctionnalités introduites dans le tutoriel :

  • Entity Framework Code First
  • LocalDB
  • Annotations de données

Création des modèles de données

Entity Framework est une infrastructure de mappage relationnel d’objets (ORM). Il vous permet d’utiliser des données relationnelles en tant qu’objets, éliminant ainsi la plupart du code d’accès aux données que vous devez généralement écrire. Avec Entity Framework, vous pouvez émettre des requêtes à l’aide de LINQ, puis récupérer et manipuler des données en tant qu’objets fortement typés. LINQ fournit des modèles pour interroger et mettre à jour des données. L’utilisation d’Entity Framework vous permet de vous concentrer sur la création du reste de votre application, plutôt que sur les principes fondamentaux de l’accès aux données. Plus loin dans cette série de tutoriels, nous vous montrerons comment utiliser les données pour remplir les requêtes de navigation et de produit.

Entity Framework prend en charge un paradigme de développement appelé Code First. Code First vous permet de définir vos modèles de données à l’aide de classes. Une classe est une construction qui vous permet de créer des types personnalisés en regroupant des variables d’autres types, méthodes et événements. Vous pouvez mapper des classes à une base de données existante ou les utiliser pour générer une base de données. Dans ce tutoriel, vous allez créer les modèles de données en écrivant des classes de modèle de données. Ensuite, vous allez laisser Entity Framework créer la base de données à la volée à partir de ces nouvelles classes.

Vous allez commencer par créer les classes d’entités qui définissent les modèles de données pour l’application Web Forms. Ensuite, vous allez créer une classe de contexte qui gère les classes d’entité et fournit l’accès aux données à la base de données. Vous allez également créer une classe d’initialiseur que vous utiliserez pour remplir la base de données.

Entity Framework et références

Par défaut, Entity Framework est inclus lorsque vous créez une application web ASP.NET à l’aide du modèle Web Forms. Entity Framework peut être installé, désinstallé et mis à jour en tant que package NuGet.

Ce package NuGet inclut les assemblys d’exécution suivants dans votre projet :

  • EntityFramework.dll : tout le code d’exécution courant utilisé par Entity Framework
  • EntityFramework.SqlServer.dll : fournisseur microsoft SQL Server pour Entity Framework

Classes d’entités

Les classes que vous créez pour définir le schéma des données sont appelées classes d’entité. Si vous débutez dans la conception de base de données, considérez les classes d’entité comme des définitions de table d’une base de données. Chaque propriété de la classe spécifie une colonne dans la table de la base de données. Ces classes fournissent une interface légère et relationnelle entre le code orienté objet et la structure de table relationnelle de la base de données.

Dans ce tutoriel, vous allez commencer par ajouter des classes d’entités simples représentant les schémas des produits et des catégories. La classe products contiendra des définitions pour chaque produit. Le nom de chacun des membres de la classe de produit est , , , , , , et CategoryIDCategory. ImagePathUnitPriceDescriptionProductNameProductID La classe category contient des définitions pour chaque catégorie à laquelle un produit peut appartenir, comme Car, Boat ou Plane. Le nom de chacun des membres de la classe de catégorie est CategoryID, CategoryName, Descriptionet Products. Chaque produit appartient à l’une des catégories. Ces classes d’entités seront ajoutées au dossier Modèles existant du projet.

  1. Dans Explorateur de solutions, cliquez avec le bouton droit sur le dossier Modèles, puis sélectionnez Ajouter ->Nouvel élément.

    Capture d’écran de la fenêtre Explorateur de solutions avec le dossier Modèles mis en évidence et les menus déroulants Ajouter et Nouvel élément sélectionnés.

    La boîte de dialogue Ajouter un nouvel élément s’affiche.

  2. Sous Visual C# dans le volet Installé à gauche, sélectionnez Code.

    Capture d’écran de la fenêtre Ajouter un nouvel élément montrant le volet Installé à gauche avec Visual C# ouvert et Code sélectionné.

  3. Sélectionnez Classe dans le volet central et nommez cette nouvelle classe Product.cs.

  4. Cliquez sur Add.
    Le nouveau fichier de classe s’affiche dans l’éditeur.

  5. Remplacez le code par défaut par le code suivant :

    using System.ComponentModel.DataAnnotations;
    
    namespace WingtipToys.Models
    {
        public class Product
        {
            [ScaffoldColumn(false)]
            public int ProductID { get; set; }
    
            [Required, StringLength(100), Display(Name = "Name")]
            public string ProductName { get; set; }
    
            [Required, StringLength(10000), Display(Name = "Product Description"), DataType(DataType.MultilineText)]
            public string Description { get; set; }
    
            public string ImagePath { get; set; }
    
            [Display(Name = "Price")]
            public double? UnitPrice { get; set; }
    
            public int? CategoryID { get; set; }
    
            public virtual Category Category { get; set; }
        }
    }
    
  6. Créez une autre classe en répétant les étapes 1 à 4, mais nommez la nouvelle classe Category.cs et remplacez le code par défaut par le code suivant :

    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    
    namespace WingtipToys.Models
    {
        public class Category
        {
            [ScaffoldColumn(false)]
            public int CategoryID { get; set; }
    
            [Required, StringLength(100), Display(Name = "Name")]
            public string CategoryName { get; set; }
    
            [Display(Name = "Product Description")]
            public string Description { get; set; }
    
            public virtual ICollection<Product> Products { get; set; }
        }
    }
    

Comme mentionné précédemment, la Category classe représente le type de produit que l’application est conçue pour vendre (par exemple, « Cars », « Boats », « Rockets », etc.), et la Product classe représente les produits individuels (jouets) dans la base de données. Chaque instance d’un Product objet correspond à une ligne dans une table de base de données relationnelle, et chaque propriété de la classe Product mappe à une colonne de la table de base de données relationnelle. Plus loin dans ce tutoriel, vous passerez en revue les données de produit contenues dans la base de données.

Annotations de données

Vous avez peut-être remarqué que certains membres des classes ont des attributs spécifiant des détails sur le membre, tels que [ScaffoldColumn(false)]. Il s’agit d’annotations de données. Les attributs d’annotation de données peuvent décrire comment valider l’entrée utilisateur pour ce membre, spécifier sa mise en forme et spécifier la façon dont elle est modélisée lors de la création de la base de données.

Context, classe

Pour commencer à utiliser les classes pour l’accès aux données, vous devez définir une classe de contexte. Comme mentionné précédemment, la classe de contexte gère les classes d’entité (telles que la Product classe et la Category classe) et fournit l’accès aux données à la base de données.

Cette procédure ajoute une nouvelle classe de contexte C# au dossier Models .

  1. Cliquez avec le bouton droit sur le dossier Modèles , puis sélectionnez Ajouter ->Nouvel élément.
    La boîte de dialogue Ajouter un nouvel élément s’affiche.

  2. Sélectionnez Classe dans le volet central, nommez-la ProductContext.cs , puis cliquez sur Ajouter.

  3. Remplacez le code par défaut contenu dans la classe par le code suivant :

    using System.Data.Entity;
    namespace WingtipToys.Models
    {
        public class ProductContext : DbContext
        {
            public ProductContext() : base("WingtipToys")
            {
            }
            public DbSet<Category> Categories { get; set; }
            public DbSet<Product> Products { get; set; }
        }
    }
    

Ce code ajoute l’espace System.Data.Entity de noms afin que vous ayez accès à toutes les fonctionnalités principales d’Entity Framework, notamment la possibilité d’interroger, d’insérer, de mettre à jour et de supprimer des données en travaillant avec des objets fortement typés.

La ProductContext classe représente le contexte de base de données de produit Entity Framework, qui gère l’extraction, le stockage et la mise à jour Product des instances de classe dans la base de données. La ProductContext classe dérive de la DbContext classe de base fournie par Entity Framework.

Classe Initializer

Vous devrez exécuter une logique personnalisée pour initialiser la base de données la première fois que le contexte est utilisé. Cela permet d’ajouter des données initiales à la base de données afin que vous puissiez afficher immédiatement les produits et les catégories.

Cette procédure ajoute une nouvelle classe d’initialiseur C# au dossier Models .

  1. Créez-en un autre Class dans le dossier Models et nommez-le ProductDatabaseInitializer.cs.

  2. Remplacez le code par défaut contenu dans la classe par le code suivant :

    using System.Collections.Generic;
    using System.Data.Entity;
    
    namespace WingtipToys.Models
    {
      public class ProductDatabaseInitializer : DropCreateDatabaseIfModelChanges<ProductContext>
      {
        protected override void Seed(ProductContext context)
        {
          GetCategories().ForEach(c => context.Categories.Add(c));
          GetProducts().ForEach(p => context.Products.Add(p));
        }
    
        private static List<Category> GetCategories()
        {
          var categories = new List<Category> {
                    new Category
                    {
                        CategoryID = 1,
                        CategoryName = "Cars"
                    },
                    new Category
                    {
                        CategoryID = 2,
                        CategoryName = "Planes"
                    },
                    new Category
                    {
                        CategoryID = 3,
                        CategoryName = "Trucks"
                    },
                    new Category
                    {
                        CategoryID = 4,
                        CategoryName = "Boats"
                    },
                    new Category
                    {
                        CategoryID = 5,
                        CategoryName = "Rockets"
                    },
                };
    
          return categories;
        }
    
        private static List<Product> GetProducts()
        {
          var products = new List<Product> {
                    new Product
                    {
                        ProductID = 1,
                        ProductName = "Convertible Car",
                        Description = "This convertible car is fast! The engine is powered by a neutrino based battery (not included)." + 
                                      "Power it up and let it go!", 
                        ImagePath="carconvert.png",
                        UnitPrice = 22.50,
                        CategoryID = 1
                   },
                    new Product 
                    {
                        ProductID = 2,
                        ProductName = "Old-time Car",
                        Description = "There's nothing old about this toy car, except it's looks. Compatible with other old toy cars.",
                        ImagePath="carearly.png",
                        UnitPrice = 15.95,
                         CategoryID = 1
                   },
                    new Product
                    {
                        ProductID = 3,
                        ProductName = "Fast Car",
                        Description = "Yes this car is fast, but it also floats in water.",
                        ImagePath="carfast.png",
                        UnitPrice = 32.99,
                        CategoryID = 1
                    },
                    new Product
                    {
                        ProductID = 4,
                        ProductName = "Super Fast Car",
                        Description = "Use this super fast car to entertain guests. Lights and doors work!",
                        ImagePath="carfaster.png",
                        UnitPrice = 8.95,
                        CategoryID = 1
                    },
                    new Product
                    {
                        ProductID = 5,
                        ProductName = "Old Style Racer",
                        Description = "This old style racer can fly (with user assistance). Gravity controls flight duration." + 
                                      "No batteries required.",
                        ImagePath="carracer.png",
                        UnitPrice = 34.95,
                        CategoryID = 1
                    },
                    new Product
                    {
                        ProductID = 6,
                        ProductName = "Ace Plane",
                        Description = "Authentic airplane toy. Features realistic color and details.",
                        ImagePath="planeace.png",
                        UnitPrice = 95.00,
                        CategoryID = 2
                    },
                    new Product
                    {
                        ProductID = 7,
                        ProductName = "Glider",
                        Description = "This fun glider is made from real balsa wood. Some assembly required.",
                        ImagePath="planeglider.png",
                        UnitPrice = 4.95,
                        CategoryID = 2
                    },
                    new Product
                    {
                        ProductID = 8,
                        ProductName = "Paper Plane",
                        Description = "This paper plane is like no other paper plane. Some folding required.",
                        ImagePath="planepaper.png",
                        UnitPrice = 2.95,
                        CategoryID = 2
                    },
                    new Product
                    {
                        ProductID = 9,
                        ProductName = "Propeller Plane",
                        Description = "Rubber band powered plane features two wheels.",
                        ImagePath="planeprop.png",
                        UnitPrice = 32.95,
                        CategoryID = 2
                    },
                    new Product
                    {
                        ProductID = 10,
                        ProductName = "Early Truck",
                        Description = "This toy truck has a real gas powered engine. Requires regular tune ups.",
                        ImagePath="truckearly.png",
                        UnitPrice = 15.00,
                        CategoryID = 3
                    },
                    new Product
                    {
                        ProductID = 11,
                        ProductName = "Fire Truck",
                        Description = "You will have endless fun with this one quarter sized fire truck.",
                        ImagePath="truckfire.png",
                        UnitPrice = 26.00,
                        CategoryID = 3
                    },
                    new Product
                    {
                        ProductID = 12,
                        ProductName = "Big Truck",
                        Description = "This fun toy truck can be used to tow other trucks that are not as big.",
                        ImagePath="truckbig.png",
                        UnitPrice = 29.00,
                        CategoryID = 3
                    },
                    new Product
                    {
                        ProductID = 13,
                        ProductName = "Big Ship",
                        Description = "Is it a boat or a ship. Let this floating vehicle decide by using its " + 
                                      "artifically intelligent computer brain!",
                        ImagePath="boatbig.png",
                        UnitPrice = 95.00,
                        CategoryID = 4
                    },
                    new Product
                    {
                        ProductID = 14,
                        ProductName = "Paper Boat",
                        Description = "Floating fun for all! This toy boat can be assembled in seconds. Floats for minutes!" + 
                                      "Some folding required.",
                        ImagePath="boatpaper.png",
                        UnitPrice = 4.95,
                        CategoryID = 4
                    },
                    new Product
                    {
                        ProductID = 15,
                        ProductName = "Sail Boat",
                        Description = "Put this fun toy sail boat in the water and let it go!",
                        ImagePath="boatsail.png",
                        UnitPrice = 42.95,
                        CategoryID = 4
                    },
                    new Product
                    {
                        ProductID = 16,
                        ProductName = "Rocket",
                        Description = "This fun rocket will travel up to a height of 200 feet.",
                        ImagePath="rocket.png",
                        UnitPrice = 122.95,
                        CategoryID = 5
                    }
                };
    
          return products;
        }
      }
    }
    

Comme vous pouvez le voir dans le code ci-dessus, lorsque la base de données est créée et initialisée, la Seed propriété est remplacée et définie. Lorsque la Seed propriété est définie, les valeurs des catégories et des produits sont utilisées pour remplir la base de données. Si vous tentez de mettre à jour les données initiales en modifiant le code ci-dessus une fois la base de données créée, vous ne verrez aucune mise à jour lorsque vous exécutez l’application web. La raison en est que le code ci-dessus utilise une implémentation de la DropCreateDatabaseIfModelChanges classe pour reconnaître si le modèle (schéma) a changé avant de réinitialiser les données initiales. Si aucune modification n’est apportée aux Category classes d’entité et Product , la base de données n’est pas réinitialisée avec les données initiales.

Notes

Si vous souhaitez que la base de données soit recréée chaque fois que vous avez exécuté l’application, vous pouvez utiliser la DropCreateDatabaseAlways classe au lieu de la DropCreateDatabaseIfModelChanges classe . Toutefois, pour cette série de tutoriels, utilisez la DropCreateDatabaseIfModelChanges classe .

À ce stade de ce tutoriel, vous disposez d’un dossier Models avec quatre nouvelles classes et une classe par défaut :

Créer le dossier Couche d’accès aux données - Modèles

Configuration de l’application pour utiliser le modèle de données

Maintenant que vous avez créé les classes qui représentent les données, vous devez configurer l’application pour qu’elle utilise les classes. Dans le fichier Global.asax , vous ajoutez du code qui initialise le modèle. Dans le fichier Web.config , vous ajoutez des informations qui indiquent à l’application la base de données que vous allez utiliser pour stocker les données représentées par les nouvelles classes de données. Le fichier Global.asax peut être utilisé pour gérer des événements ou des méthodes d’application. Le fichier Web.config vous permet de contrôler la configuration de votre application web ASP.NET.

Mise à jour du fichier Global.asax

Pour initialiser les modèles de données au démarrage de l’application, vous devez mettre à jour le Application_Start gestionnaire dans le fichier Global.asax.cs .

Notes

Dans Explorateur de solutions, vous pouvez sélectionner le fichier Global.asax ou le fichier Global.asax.cs pour modifier le fichier Global.asax.cs.

  1. Ajoutez le code suivant mis en surbrillance en jaune à la Application_Start méthode dans le fichier Global.asax.cs .

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Optimization;
    using System.Web.Routing;
    using System.Web.Security;
    using System.Web.SessionState;
    using System.Data.Entity;
    using WingtipToys.Models;
    
    namespace WingtipToys
    {
        public class Global : HttpApplication
        {
            void Application_Start(object sender, EventArgs e)
            {
                // Code that runs on application startup
                RouteConfig.RegisterRoutes(RouteTable.Routes);
                BundleConfig.RegisterBundles(BundleTable.Bundles);
    
                // Initialize the product database.
                Database.SetInitializer(new ProductDatabaseInitializer());
            }
        }
    }
    

Notes

Votre navigateur doit prendre en charge HTML5 pour afficher le code mis en surbrillance en jaune lors de l’affichage de cette série de tutoriels dans un navigateur.

Comme indiqué dans le code ci-dessus, lorsque l’application démarre, l’application spécifie l’initialiseur qui s’exécutera lors de la première consultation des données. Les deux espaces de noms supplémentaires sont nécessaires pour accéder à l’objet Database et à l’objet ProductDatabaseInitializer .

Modification du fichier Web.Config

Bien qu’Entity Framework Code First génère une base de données pour vous dans un emplacement par défaut lorsque la base de données est remplie avec des données de départ, l’ajout de vos propres informations de connexion à votre application vous permet de contrôler l’emplacement de la base de données. Vous spécifiez cette connexion de base de données à l’aide d’une chaîne de connexion dans le fichier Web.config de l’application à la racine du projet. En ajoutant une nouvelle chaîne de connexion, vous pouvez diriger l’emplacement de la base de données (wingtiptoys.mdf) à générer dans le répertoire de données de l’application (App_Data), plutôt que son emplacement par défaut. Cette modification vous permettra de rechercher et d’inspecter le fichier de base de données plus loin dans ce tutoriel.

  1. Dans Explorateur de solutions, recherchez et ouvrez le fichier Web.config.

  2. Ajoutez la chaîne de connexion mise en surbrillance en jaune à la <connectionStrings> section du fichier Web.config comme suit :

    <connectionStrings>
    <add name="DefaultConnection" connectionString="Data Source=(LocalDb)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\aspnet-WingtipToys-20131119102907.mdf;Initial Catalog=aspnet-WingtipToys-20131119102907;Integrated Security=True"
    providerName="System.Data.SqlClient" />
    <add name="WingtipToys"
    connectionString="Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\wingtiptoys.mdf;Integrated Security=True"
    providerName="System.Data.SqlClient" />
    </connectionStrings>
    

Lorsque l’application est exécutée pour la première fois, elle génère la base de données à l’emplacement spécifié par la chaîne de connexion. Mais avant d’exécuter l’application, nous allons d’abord la générer.

Génération de l'application

Pour vous assurer que toutes les classes et les modifications apportées à votre application web fonctionnent, vous devez générer l’application.

  1. Dans le menu Déboguer , sélectionnez Générer WingtipToys.
    La fenêtre Sortie s’affiche et, si tout s’est bien passé, un message de réussite s’affiche.

    Créer la couche d’accès aux données - Fenêtres de sortie

Si vous rencontrez une erreur, case activée les étapes ci-dessus. Les informations de la fenêtre Sortie indiquent quel fichier rencontre un problème et où une modification est nécessaire dans le fichier. Ces informations vous permettront de déterminer quelle partie des étapes ci-dessus doit être examinée et corrigée dans votre projet.

Résumé

Dans ce tutoriel de la série, vous avez créé le modèle de données et ajouté le code qui sera utilisé pour initialiser et amorcer la base de données. Vous avez également configuré l’application pour utiliser les modèles de données lors de l’exécution de l’application.

Dans le tutoriel suivant, vous allez mettre à jour l’interface utilisateur, ajouter la navigation et récupérer des données de la base de données. Cela entraîne la création automatique de la base de données en fonction des classes d’entité que vous avez créées dans ce didacticiel.

Ressources supplémentaires

Vue d’ensemble d’Entity Framework
Guide du débutant pour l’ADO.NET Entity Framework
Code First Development avec Entity FrameworkCode First Relationships Fluent API
Annotations de données Code First
Améliorations de la productivité pour Entity Framework