Поделиться через


Наследование (модель EDM)

В модели Entity Data Model (EDM) наследование позволяет расширять функции типов при помощи производного типа.

Обычно модель, которую использует приложение, имеет много разных типов. Некоторые типы сущности моделируют в приложениях для бизнеса разные концепции, например «клиент» и «заказ» . Эти типы данных не имеют общих членов, однако существуют другие типы, которые больше похожи друг на друга. В качестве примера рассмотрим типы «клиент» и «служащий». Хотя эти типы моделируют разные концепции, у них есть базовая общность: оба типа представляют людей, участвующих в деловых отношениях, и оба имеют свойства для хранения таких сведений, как ФИО, адрес и номер телефона.

В модели EDM наследование позволяет одному типу быть производным другого типа. Например, типы Employee и Customer могут наследовать от типа Contact. В данном случае Contact называется базовым типом, а Employee и Customer называются производными типами.

Наследование не обязательно ограничивается одним уровнем: производный тип может быть базовым типом другого типа сущности. Например, тип Employee является базовым типом Manager, тип Customer является базовым типом PreferredCustomer и так далее. Таким образом строятся иерархии наследования.

Как и среда CLR, система EDM поддерживает только одиночное наследование типов данных. Тип сущности может наследовать свойства напрямую только от одного супертипа.

NoteПримечание.

Поскольку в системе EDM не реализуются методы, наследование методов не поддерживается. Вспомогательные методы в системе EDM реализованы в разделяемых классах. Дополнительные сведения см. в разделе Вспомогательные методы (модель EDM).

Примеры наследования

В следующих примерах демонстрируется частичная спецификация языка CSDL для описанной ранее иерархии наследования:

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

Одним из предназначений наследования является совместное использование несколькими типами фундаментальной структуры. Другой причиной использования наследования является расширяемость. Даже после реализации и внедрения в приложение иерархии наследования разработчики могут расширять типы при помощи наследования.

Принцип полиморфизма или заменяемости значений в объектно-ориентированном программировании базируется на наследовании. Каждый экземпляр производного типа данных также является экземпляром своего базового типа. Например, если тип Manager является производным типа Employee, то каждый экземпляр типа Manager также является экземпляром типа Employee. При запросе всех сотрудников (базовый тип) возвращаются также и все менеджеры (производный тип).

Дополнительные сведения о наследовании см. в разделах Как Задать модель с наследованием «одна таблица на тип» и Как определить модель с наследованием типа «одна таблица на иерархию» (платформа Entity Framework).

Реализация наследования

По определению в языке CSDL иерархия наследования должна реализовываться в таблицах базы данных, в которых хранятся данные приложения, построенного по модели EDM. Есть несколько способов структурирования типов, составляющих иерархию наследования, в таблицах базы данных.

Во всех реализациях ключевая структура базовых и производных типов должна быть одинаковой. То есть если тип Customer является производным типа Person, оба типа, Customer и Person, должны указывать одинаковое ключевое свойство или свойства.

При реализации наследования в нескольких таблицах ключевому свойству назначается одинаковое значение в более чем одной таблице, чтобы идентифицировать производные типы как экземпляры базовых типов.

Реализации наследования в спецификации сопоставления могут использовать индикатор IsTypeOf<T> в EntityTypeMapping, чтобы указать, что, например, тип Customer также является типом базового типа Person. В концептуальной схеме и схеме хранения существует также атрибут BaseType объекта EntityType, который можно использовать, чтобы обозначать базовый тип производной сущности.

Модель «одна таблица на иерархию»

В наследовании, основанном на модели «одна таблица на иерархию», несколько типов в иерархии определяются с использованием одной таблицы базы данных. В этой модели тип в иерархии наследования идентифицируется явным условием в спецификации сопоставления.

Столбец дискриминаторов включается в эту таблицу, чтобы обозначать каждый тип, а условие ссылается на назначенное значение столбца для каждого типа. Например, условие может указывать, что значение столбца EntityType равно P для типа Person, а для типа Customer — C.

В следующем примере сопоставления демонстрируется условное сопоставление типов Customer и 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>

Модель «одна таблица на тип»

В наследовании, основанном на модели «одна таблица на тип», базовый или исходный тип хранится в одной таблице, а для производных типов используются дополнительные таблицы. Поля, характерные для производных типов, появляются только в таблицах, в которых хранятся производные типы. Сопоставление сущностей в этой модели наследования охватывает несколько физических таблиц. Типы в иерархии отличаются наличием или отсутствием строки в таблице. Ключевому свойству во всех таблицах назначается одинаковое ключевое значение.

Атрибут BaseType типа сущности EntityType можно использовать в концептуальной схеме или схеме хранения для обозначения наследования от базового типа. Индикатор IsTypeOf<T> можно использовать в спецификации сопоставления для обозначения базового типа и устранения повторяющегося синтаксиса сопоставления.

В следующем примере сопоставления показаны два отдельных сопоставления для типов Customer и Person. В атрибутах TypeName элементов EntityTypeMapping и состоит отличие типов Person и Customer. Для каждого типа имеется своя таблица. Тип и таблица сущности Customer содержат свойство и столбец NumYears, которые не включены в базовый тип.

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

См. также

Задачи

Как задать модель с наследованием «таблица для типа» (платформа Entity Framework)
Как определить модель с наследованием типа «одна таблица на иерархию» (платформа Entity Framework)

Основные понятия

Типы модели EDM
Вспомогательные методы (модель EDM)
Наследование в модели EDM (сценарии приложений)