Condividi tramite


Ereditarietà (EDM)

In Entity Data Model (EDM) l'ereditarietà consente a un tipo derivato di estendere le funzionalità di un altro tipo.

In genere, il modello utilizzato da un'applicazione include molti tipi diversi. Alcuni tipi di entità modellano concetti distinti, ad esempio Customer e Order****in un'applicazione aziendale. Questi tipi di dati non condividono alcun membro, ma vi sono altri tipi più simili tra loro. Si considerino, ad esempio, i tipi Customer ed Employee Anche se questi tipi modellano concetti diversi, hanno un elemento sottostante comune, ovvero rappresentano entrambi persone coinvolte in relazioni aziendali ed entrambi includono proprietà per l'archiviazione di informazioni quali nome, indirizzo e numero di telefono.

L'ereditarietà EDM consente di derivare un tipo da un altro tipo. Employee e Customer possono ad esempio ereditare entrambi dal tipo Contact. In questo caso, Contact è chiamato tipo di base, mentre Employee e Customer sono chiamati tipi derivati.

L'ereditarietà non deve necessariamente interrompersi a un solo livello. Un tipo derivato può essere il tipo di base di un altro tipo di entità. Employee è ad esempio un tipo di base di Manager, Customer è un tipo di base di PreferredCustomer e così via. In questo modo, vengono compilate le gerarchie di ereditarietà.

Come nel caso di Common Language Runtime (CLR), il sistema EDM supporta solo l'ereditarietà singola dei tipi di dati. Un tipo di entità può solo ereditare direttamente le proprietà da un supertipo.

NoteNota

Poiché il sistema EDM non implementa metodi, l'ereditarietà dei metodi non è supportata. In EDM i metodi di supporto sono implementati nelle classi parziali. Per ulteriori informazioni, vedere Metodi di supporto (EDM).

Esempi di ereditarietà

Nell'esempio seguente è illustrata una specifica CSDL (Conceptual Schema Definition Language) parziale per la gerarchia di ereditarietà descritta in precedenza:

  <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 -->

Uno scopo dell'ereditarietà è quello di condividere una struttura di base tra più tipi. Un altro motivo per utilizzare l'ereditarietà è rappresentato dall'estensibilità. Anche dopo che una gerarchia di ereditarietà è stata implementata e distribuita in un'applicazione, gli sviluppatori possono estendere i tipi tramite l'ereditarietà.

Il concetto di polimorfismo o sostituibilità del valore della programmazione orientata a oggetti dipende dall'ereditarietà. Ogni istanza di un tipo di dati derivato è anche un'istanza del relativo tipo di base. Se, ad esempio, Manager è derivato da Employee, ogni istanza di Manager è anche un'istanza di Employee. Quando si esegue una query per tutti i dipendenti (tipo di base), si ottengono anche tutti i dirigenti (tipo derivato).

Per ulteriori informazioni sull'ereditarietà, vedere Procedura: definire un modello con ereditarietà tabella per tipo e Procedura: definire un modello con ereditarietà tabella per gerarchia (Entity Framework).

Implementazione dell'ereditarietà

Una gerarchia di ereditarietà come definita in CSDL deve essere implementata nelle tabelle di database in cui vengono archiviati i dati per un'applicazione compilata in base al modello EDM. I tipi in una gerarchia di ereditarietà possono essere organizzati in diversi modi nelle tabelle di database.

In tutte le implementazioni la struttura Key dei tipi di base e dei tipi derivati deve essere identica. Questo significa che se un tipo Customer è derivato dal tipo Person, entrambi i tipi Customer e Person devono specificare la stessa o le stesse proprietà Key.

Nelle implementazioni dell'ereditarietà in più tabelle, viene assegnato lo stesso valore alla proprietà Key in più di una tabella per identificare i tipi derivati come istanze dei tipi predecessore.

Nella specifica di mapping le implementazioni dell'ereditarietà possono utilizzare l'indicatore IsTypeOf<T> in EntityTypeMapping per specificare che, ad esempio, il tipo Customer è anche un tipo del tipo di base Person. Sia nello schema concettuale che in quello di archiviazione è inoltre disponibile un attributo BaseType di EntityType che è possibile utilizzare per designare il tipo di base di un'entità derivata.

Modello tabella per gerarchia

L'ereditarietà basata sul modello tabella per gerarchia specifica più tipi nella gerarchia utilizzando la stessa tabella di database. In questo modello una condizione esplicita nella specifica di mapping identifica il tipo nella gerarchia di ereditarietà.

Nella tabella è inclusa una colonna discriminatore che consente di distinguere ogni tipo e la condizione fa riferimento a un valore assegnato della colonna per ogni tipo. La condizione può ad esempio specificare che il valore della colonna EntityType è uguale a P per il tipo Person o a C per il tipo Customer.

Nell'esempio seguente viene illustrato il mapping condizionale dei tipi Customer e 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>

Modello tabella per tipo

Nell'ereditarietà basata sul modello tabella per tipo il tipo di base o predecessore è archiviato in una tabella ma vengono utilizzate tabelle aggiuntive per i tipi derivati. I campi specifici dei tipi derivati sono presenti solo nelle tabelle che rappresentano i tipi derivati. Il mapping per le entità di questo modello di ereditarietà si estende in molte tabelle fisiche. La presenza o l'assenza di una riga in una tabella consente di distinguere i tipi nella gerarchia. Alla proprietà Key in tutte le tabelle è assegnato lo stesso valore.

L'attributo BaseType di EntityType può essere utilizzato negli schemi concettuali e di archiviazione per indicare l'ereditarietà dal tipo di base. L'indicatore IsTypeOf<T> nella specifica di mapping può essere utilizzato per indicare il tipo di base ed eliminare la sintassi di mapping duplicata.

Nell'esempio seguente vengono illustrati due mapping distinti per i tipi Customer e Person. Gli attributi ****TypeName degli elementi EntityTypeMapping distinguono i tipi Person e Customer. È presente una tabella per ogni tipo. La tabella e il tipo di entità Customer contengono la proprietà NumYears e la colonna non inclusa nel tipo di 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>

Vedere anche

Attività

Procedura: definire un modello con ereditarietà tabella per tipo (Entity Framework)
Procedura: definire un modello con ereditarietà tabella per gerarchia (Entity Framework)

Concetti

Tipi EDM (Entity Data Model)
Metodi di supporto (EDM)
Ereditarietà in Entity Data Model (scenari applicativi)