Héritage (EDM)

Dans le modèle EDM (Modèle de données d'entité), l'héritage permet à un type dérivé d'étendre les fonctionnalités d'un autre type.

Généralement, le modèle utilisé par une application comprend de nombreux types différents. Certains types d'entités modélisent des concepts distincts, comme Customer (client) et Order (commande)****dans une application de gestion. Ces types de données ne partagent aucun membre, mais certains types présentent entre eux plus de similitudes que d'autres. Considérez, par exemple, les types Customer et Employee (employé). Bien que modélisant des concepts différents, ils affichent une certaine similitude : tous deux représentent des personnes impliquées dans des relations d'affaires et tous deux incluent des propriétés pour le stockage d'informations telles que nom, adresse et numéro de téléphone.

L'héritage EDM permet à un type de dériver d'un autre type. Par exemple, Employee et Customer peuvent tous deux hériter du type Contact. Dans ce cas, Contact est appelé le type de base. Employee et Customer sont appelés les types dérivés.

L'héritage n'est pas limité à un seul niveau : un type dérivé peut constituer le type de base d'un autre type d'entité. Par exemple, Employee est un type de base de Manager et Customer un type de base de PreferredCustomer, et ainsi de suite. C'est de cette manière que s'élaborent les hiérarchies d'héritage.

Comme le CLR (Common Language Runtime), le système EDM prend uniquement en charge l'héritage simple de types de données. Un type d'entité peut hériter directement des propriétés d'un seul supertype.

NoteRemarque

Le système EDM n'implémentant pas de méthodes, leur héritage n'est pas pris en charge. Dans le modèle EDM, les méthodes d'assistance sont implémentées dans des classes partielles. Pour plus d'informations, voir Méthodes d'assistance (EDM).

Exemples d'héritage

L'exemple suivant présente une spécification CSDL (Conceptual Schema Definition Language) partielle pour la hiérarchie d'héritage décrite plus haut :

  <EntityType Name="Contact">
    <Key>
      <PropertyRef Name="ContactId" />
    </Key>
    <Property Name="ContactId" Type="Int32" Nullable="false" />
    <Property Name="Name" Type="String" />
    <Property Name="Address" Type="Address" />
    <Property Name="Phone" Type="String" />
  </EntityType>

  <EntityType Name="Customer" BaseType="Contact">
    <Property Name="CustomerID" Type="String" />
    <Property Name="CompanyName" Type="String" />
  </EntityType>

  <EntityType Name="PreferredCustomer" BaseType="Customer">
    <Property Name="PreferenceCode" Type="String" />
    <Property Name="CreditLimit" Type="Decimal" />
  </EntityType>
  <!-- Similar Declarations for Employee and Manager -->

L'une des finalités de l'héritage est de disposer d'une structure de base commune à plusieurs types. L'héritage présente en outre l'avantage de l'extensibilité. Grâce à lui, les développeurs peuvent étendre les types même après qu'une hiérarchie d'héritage a été implémentée et déployée dans une application.

Le concept de programmation orientée du polymorphisme ou la capacité des valeurs à être substituées dépend de l'héritage. Chaque instance d'un type de données dérivé est aussi une instance de son type de base. Par exemple, si Manager est dérivé d'Employee, chaque instance de Manager est aussi une instance d'un Employee. Une requête visant à obtenir tous les employés (employee, type de base) donnera aussi tous les responsables (manager, type dérivé).

Pour plus d'informations sur l'héritage, voir Procédure : définir un modèle à l'aide de l'héritage TPT (table par type) et Procédure : définir un modèle avec l'héritage TPH (table par hiérarchie) (Entity Framework).

Implémentation de l'héritage

Une hiérarchie d'héritage telle que définie en CSDL doit être implémentée dans les tables de base de données qui stockent les données d'une application construite sur le modèle EDM. Les types d'une hiérarchie d'héritage peuvent être structurés dans les tables de base de données de différentes manières.

Cependant, dans toutes les implémentations, la structure de clés des types de base et dérivés doit être identique. Ainsi, si un type Customer est dérivé du type Person, les types Customer et Person doivent tous deux spécifier la ou les mêmes propriétés de clé.

Dans les implémentations où l'héritage concerne plusieurs tables, la même valeur est affectée à la propriété de clé dans plusieurs tables, afin d'identifier les types dérivés en tant qu'instances des types ancêtres.

Dans la spécification de mappage, les implémentations de l'héritage peuvent utiliser l'indicateur IsTypeOf<T> d'EntityTypeMapping pour spécifier, par exemple, que le type Customer est également un type du type de base Person. Un attribut BaseType d'EntityType présent dans le schéma conceptuel et le schéma de stockage peut aussi servir à désigner le type de base d'une entité dérivée.

Modèle TPH (table par hiérarchie)

L'héritage basé sur le modèle TPH (table par hiérarchie) spécifie plusieurs types dans la hiérarchie en utilisant la même table de base de données. Dans ce modèle, une condition explicite de la spécification de mappage identifie le type dans la hiérarchie d'héritage.

Une colonne de discriminateur est incluse dans la table pour distinguer un type d'un autre, et la condition fait référence, pour chaque type, à une valeur définie de la colonne. Par exemple, la condition peut spécifier que la valeur de la colonne EntityType est P pour le type Person ou C pour le type Customer.

L'exemple ci-dessous représente le mappage conditionnel des types Customer et Person.

<?xml version="1.0" encoding="utf-8"?>
<Mapping Space="C-S"
    xmlns:cdm="urn:schemas-microsoft-com:windows:storage:mapping:CS"
    xmlns="urn:schemas-microsoft-com:windows:storage:mapping:CS">

  <EntityContainerMapping>
    <EntitySetMapping Name="CCustomer1">
      <EntityTypeMapping TypeName="CNorthwind.CCustomer">
        <MappingFragment StoreEntitySet="SParty1">
          <EntityKey>
            <ScalarProperty Name="PartyID" ColumnName="PartyID" />
          </EntityKey>
          <ScalarProperty Name="PartyName" ColumnName="PartyName" />
          <ScalarProperty Name="PartyTitle" ColumnName="Title" />
          <ScalarProperty Name="ContactName" ColumnName="ContactName" />
          <Condition Value="C" ColumnName="EntityType" />
        </MappingFragment>
      </EntityTypeMapping>
    </EntitySetMapping>

    <EntitySetMapping Name="CSupplier1">
      <EntityTypeMapping TypeName="CNorthwind.CSupplier">
        <MappingFragment StoreEntitySet="SParty1">
          <EntityKey>
            <ScalarProperty Name="PartyID" ColumnName="PartyID" />
          </EntityKey>
          <ScalarProperty Name="PartyName" ColumnName="PartyName" />
          <ScalarProperty Name="PartyTitle" ColumnName="Title" />
          <ScalarProperty Name="HomePage" ColumnName="HomePage" />
          <Condition Value="S" ColumnName="EntityType" />
        </MappingFragment>
      </EntityTypeMapping>
    </EntitySetMapping>

  </EntityContainerMapping>

</Mapping>

Modèle TPT (table par type)

Dans l'héritage basé sur le modèle TPT (table par type), le type de base ou ancêtre est stocké dans une table, mais des tables supplémentaires sont utilisées pour les types dérivés. Les champs propres aux types dérivés ne sont présents que dans les tables qui représentent ces types dérivés. Le mappage des entités de ce modèle d'héritage s'étend sur plusieurs tables physiques. La présence ou l'absence d'une ligne dans une table permet de faire la distinction entre les types de la hiérarchie. La même valeur de clé est affectée à la propriété de clé dans toutes les tables.

L'attribut BaseType d'EntityType peut être utilisé dans le schéma conceptuel et le schéma de stockage pour indiquer l'héritage du type de base. L'indicateur IsTypeOf<T> de la spécification de mappage peut être utilisé pour spécifier le type de base et éliminer la syntaxe de mappage dupliquée.

L'exemple ci-dessous représente deux mappages distincts pour les types Customer et Person. Les attributs****TypeName des éléments EntityTypeMapping permettent de distinguer les types Person et Customer. Il existe une table pour chaque type. Le type d'entité et la table Customer contiennent la propriété et colonne NumYears, qui n'est pas incluse dans le type de base.

<?xml version="1.0" encoding="utf-8"?>
<Mapping Space="C-S" 
    xmlns:cdm="urn:schemas-microsoft-com:windows:storage:mapping:CS"
    xmlns="urn:schemas-microsoft-com:windows:storage:mapping:CS">

  <EntityContainerMapping EntityContainerName="CNorthwind.LOBData">
    <EntitySetMapping Name="Person1">
      <EntityTypeMapping TypeName="CNorthwind.Person">
        <MappingFragment StoreEntitySet="Person">
          <ScalarProperty Name="PersonID" ColumnName="PersonID" />
          <ScalarProperty Name="Name" ColumnName="Name" />
        </MappingFragment>
      </EntityTypeMapping>
      <EntityTypeMapping TypeName="CNorthwind.Customer">
        <MappingFragment StoreEntitySet="Customer">
          <ScalarProperty Name="PersonID" ColumnName="PersonID" />
          <ScalarProperty Name="Name" ColumnName="Name" />
          <ScalarProperty Name="NumYears" ColumnName="NumYears" />
        </MappingFragment>
      </EntityTypeMapping>
    </EntitySetMapping>
  </EntityContainerMapping>

</Mapping>

Voir aussi

Tâches

Procédure : définir un modèle avec l'héritage TPT (table par type) (Entity Framework)
Procédure : définir un modèle avec l'héritage TPH (table par hiérarchie) (Entity Framework)

Concepts

Types de modèles EDM
Méthodes d'assistance (EDM)
Héritage dans les modèles EDM (Scénarios d'application)