Héritage TPH du concepteur

Cette procédure pas à pas montre comment implémenter l’héritage table par hiérarchie (TPH) dans votre modèle conceptuel à l’aide de Entity Framework Designer (EF Designer). L’héritage TPH utilise une table de base de données pour gérer les données de tous les types d’entités d’une hiérarchie d’héritage.

Dans cette procédure pas à pas, nous allons mapper la table Person à trois types d’entités : Person (le type de base), Student (dérive de Person) et Instructor (dérive de Person). Nous allons créer un modèle conceptuel à partir de la base de données (Database First), puis modifier le modèle pour implémenter l’héritage TPH à l’aide du Concepteur EF.

Il est possible de mapper à un héritage TPH à l’aide de Model First, mais vous devrez écrire votre propre workflow de génération de base de données, ce qui est complexe. Vous devez ensuite attribuer ce workflow à la propriété Workflow de génération de base de données dans le Concepteur EF. Une alternative plus simple consiste à utiliser Code First.

Autres options d’héritage

La table par type (TPT) est un autre type d’héritage dans lequel des tables distinctes dans la base de données sont mappées aux entités qui participent à l’héritage.  Pour plus d’informations sur la façon de mapper l’héritage table par type avec le Concepteur EF, consultez Héritage TPT du Concepteur EF.

L’héritage table par type concret (TPC) et les modèles d’héritage mixte sont pris en charge par le runtime Entity Framework, mais ne sont pas pris en charge par le Concepteur EF. Si vous souhaitez utiliser TPC ou l’héritage mixte, vous avez deux options : utiliser Code First ou modifier manuellement le fichier EDMX. Si vous choisissez d’utiliser le fichier EDMX, la fenêtre Détails du mappage est placée en « mode sans échec » et vous ne pourrez pas utiliser le concepteur pour modifier les mappages.

Prérequis

Pour exécuter ce processus pas à pas, vous devez :

Configurer le projet

  • Ouvrez Visual Studio 2012.
  • Sélectionnez Fichier -> Nouveau -> Projet
  • Dans le volet gauche, cliquez sur Visual C#, puis sélectionnez le modèle Console.
  • Entrez TPHDBFirstSample comme nom.
  • Sélectionnez OK.

Créer un modèle

  • Dans l’Explorateur de solutions, cliquez avec le bouton droit sur le nom du projet, puis sélectionnez Ajouter -> Nouvel élément.
  • Sélectionnez Données dans le menu de gauche, puis sélectionnez ADO.NET Entity Data Model dans le menu des Modèles.
  • Entrez TPHModel.edmx comme nom de fichier, puis cliquez sur Ajouter.
  • Dans la boîte de dialogue Choisir le contenu du Model, sélectionnez Générer à partir de la base de données, puis cliquez sur Suivant.
  • Cliquer sur Nouvelle connexion. Dans la boîte de dialogue Propriétés de connexion, entrez le nom du serveur (par exemple, (localdb)\mssqllocaldb), sélectionnez la méthode d’authentification, tapez School comme nom de base de données, puis cliquez sur OK. La boîte de dialogue Choisir votre connexion de données est mise à jour avec vos paramètres de connexion aux bases de données.
  • Dans la boîte de dialogue Choisir vos objets de base de donnée, sous le nœud Tables, sélectionnez la table Person.
  • Cliquez sur Terminer.

Le Concepteur d’entités, qui fournit une aire de conception permettant de modifier votre modèle, est affiché. Tous les objets que vous avez sélectionnés dans la boîte de dialogue Choisir vos objets de base de données sont ajoutés au modèle.

C’est grâce à cette méthode que la table Person recherche dans la base de données.

Person Table 

Implémenter l’héritage table par hiérarchie

La table Person a la colonne Discriminator, qui peut avoir l’une des deux valeurs suivantes : « Student » et « Instructor ». Selon la valeur, la table Person est mappée à l’entité Student ou à l’entité Instructor. La table Person comporte également deux colonnes, HireDate et EnrollmentDate, qui doivent accepter la valeur Null car personne ne peut pas être à la fois étudiant et instructeur (du moins pas dans cette procédure pas à pas).

Ajouter de nouvelles entités

  • Ajoutez une nouvelle entité. Pour cela, cliquez avec le bouton droit sur un espace vide de l’aire de conception du Concepteur Entity Framework, puis sélectionnez Ajouter -> Entité.
  • Tapez Instructor comme Nom d’entité, puis sélectionnez Person dans la liste déroulante du Type de base.
  • Cliquez sur OK.
  • Ajoutez une nouvelle entité. Tapez Student comme Nom d’entité, puis sélectionnez Person dans la liste déroulante du Type de base.

Deux nouveaux types d’entités sont ajoutés à l’aire de conception. Une flèche pointe depuis les nouveaux types d’entités vers le type d’entité Person, ce qui indique que Person est le type de base des nouveaux types d’entités.

  • Cliquez avec le bouton droit sur la propriété HireDate de l’entité Person. Sélectionnez Couper (ou utilisez le raccourci Ctrl + X).
  • Cliquez avec le bouton droit sur l’entité Instructor, puis sélectionnez Coller (ou utilisez le raccourci Ctrl + V).
  • Cliquez avec le bouton droit sur la propriété HireDate, puis sélectionnez Propriétés.
  • Dans la fenêtre Propriétés, définissez la propriété Nullable sur false.
  • Cliquez avec le bouton droit sur la propriété EnrollmentDate de l’entité Person. Sélectionnez Couper (ou utilisez le raccourci Ctrl + X).
  • Cliquez avec le bouton droit sur l’entité Student, puis sélectionnez Coller (ou utilisez le raccourci Ctrl + V).
  • Sélectionnez la propriété EnrollmentDate et définissez la propriété Nullable sur false.
  • Sélectionnez le type d’entité Person. Dans la fenêtre Propriétés, définissez sa propriété Abstract sur true.
  • Supprimez la propriété Discriminator de Person. La raison pour laquelle elle doit être supprimée est expliquée dans la section suivante.

Mapper les entités

  • Cliquez avec le bouton droit sur Instructor, puis sélectionnez Mappage de table. L’entité Instructor est sélectionnée dans la fenêtre Détails du mappage.

  • Cliquez sur <Ajouter une table ou une vue> dans la fenêtre Détails du mappage. Le champ <Ajouter une table ou une vue> devient une liste déroulante de tables ou de vues auxquelles l’entité sélectionnée peut être mappée.

  • Sélectionnez Person dans la liste déroulante.

  • La fenêtre Détails de mappage est mise à jour avec les mappages de colonnes par défaut et une option permettant l’ajout d’une condition.

  • Cliquez sur <Ajouter une condition>. Le champ <Ajouter une condition> devient une liste déroulante de colonnes pour lesquelles des conditions peuvent être définies.

  • Sélectionnez Discriminator dans la liste déroulante.

  • Dans la colonne Opérateur de la fenêtre Détails de mappage, sélectionnez = dans la liste déroulante.

  • Dans la colonne Valeur/Propriété, tapez Instructor. Le résultat final doit ressembler à ceci :

    Mapping Details

  • Répétez ces étapes pour le type d’entité Student, mais faites en sorte que la condition soit égale à la valeur Student.
    La raison pour laquelle nous voulions supprimer la propriété Discriminator, c’est parce qu’il est impossible de mapper une colonne de table plusieurs fois. Cette colonne sera utilisée pour le mappage conditionnel, donc elle ne peut pas être également utilisée pour le mappage de propriétés. La seule façon dont elle peut être utilisée pour les deux, c’est si une condition utilise une comparaison est Null ou n’est pas Null.

L'héritage TPH (table par hiérarchie) est maintenant implémenté.

Final TPH

Utiliser le modèle

Ouvrez le fichier Program.cs où la méthode Main est définie. Collez le code suivant dans votre fonction Main. Le code exécute trois requêtes. La première requête renvoie tous les objets Person. La deuxième requête utilise la méthode OfType pour retourner les objets Instructor. La troisième requête utilise la méthode OfType pour retourner les objets Student.

    using (var context = new SchoolEntities())
    {
        Console.WriteLine("All people:");
        foreach (var person in context.People)
        {
            Console.WriteLine("    {0} {1}", person.FirstName, person.LastName);
        }

        Console.WriteLine("Instructors only: ");
        foreach (var person in context.People.OfType<Instructor>())
        {
            Console.WriteLine("    {0} {1}", person.FirstName, person.LastName);
        }

        Console.WriteLine("Students only: ");
        foreach (var person in context.People.OfType<Student>())
        {
            Console.WriteLine("    {0} {1}", person.FirstName, person.LastName);
        }
    }