Как определить модель с наследованием типа «одна таблица на иерархию» (платформа Entity Framework)
В этом разделе описывается, как вручную создать концептуальную модель с иерархией наследования «одна таблица на иерархию». Наследование типа «одна таблица на иерархию» использует одну таблицу базы данных для сопровождения данных для всех типов сущности в иерархии наследования.
Примечание |
---|
Рекомендуется определять модель с наследованием «одна таблица на тип» с помощью ADO.NET Entity Data Model Tools.Дополнительные сведения см. в разделе Walkthrough: Mapping Inheritance - Table-per-Hierarchy. |
Далее представлены основные действия по определению модели с наследованием «одна таблица на иерархию» вручную.
Определите в концептуальной модели один набор сущностей, который содержит базовый тип сущности и производные типы. Дополнительные сведения см. в разделе Элемент EntitySet (CSDL).
Определите в концептуальной модели производные типы сущностей с помощью атрибута BaseType и определите в производных типах только ненаследуемые свойства. Дополнительные сведения см. в разделе Элемент EntityType (язык CSDL).
Выберите из базовой таблицы базы данных столбец, значение которого будет использоваться для различия между основным и производным типами. Например, если в таблице Employee есть столбец EmployeeType с целочисленным значением, то его значение можно использовать для определения того, когда базовый тип сущности Employee является одним из следующих производных типов сущности: HourlyEmployee или SalariedEmployee. Дополнительные сведения см. в следующем примере.
Столбец дискриминатора сопоставляется в рамках условия, поэтому соответствующего свойства или типов сущности в иерархии быть не может. Исключением к этому правилу является случай, когда в условии имеется сравнение Is Null или Is Not Null. В этом случае у столбца дискриминатора может быть соответствующее свойство или тип сущности.
Если у столбца дискриминатора может быть более двух значений (например, целочисленных), столбец должен допускать значение null или иметь значение по умолчанию. Тем самым гарантируется, что при создании нового типа и сохранении его в базе данных значение столбца может быть равно null или другому значению.
Условия следует использовать для сопоставления каждого производного типа в иерархии и можно использовать для сопоставления базового типа. Если базовый тип окажется абстрактным, сопоставления или условия не допускаются.
Сопоставьте базовый тип сущности и производные типы в одном элементе EntitySetMapping на языке MSL. Сопоставьте наследуемые свойства со столбцами таблицы там, где нужно. При задании значения атрибута TypeName производных типов используйте синтаксис
IsTypeOf
. Для различения типов в иерархии используйте условие сопоставления. Дополнительные сведения см. в разделах Элемент EntitySetMapping (язык MSL) и Элемент Condition (язык MSL).
В следующем примере предполагается, что установлен образец базы данных School, а проект вручную настроен для использования Entity Framework . Дополнительные сведения см. в разделах Создание образца базы данных School (краткое руководство по Entity Framework) и Настройка платформы Entity Framework (задачи Entity Framework).
Создание модели хранения
Добавьте следующий XML-файл в проект и назовите его
AdventureWorks.ssdl
.<?xml version="1.0" encoding="utf-8" ?> <Schema Namespace="AdventureWorksModel.Store" Alias="Self" Provider="System.Data.SqlClient" ProviderManifestToken="2008" xmlns:store="https://schemas.microsoft.com/ado/2007/12/edm/EntityStoreSchemaGenerator" xmlns="https://schemas.microsoft.com/ado/2009/02/edm/ssdl"> <EntityContainer Name="AdventureWorksModelStoreContainer"> <EntitySet Name="Product" EntityType="AdventureWorksModel.Store.Product" store:Type="Tables" Schema="Production" /> </EntityContainer> <EntityType Name="Product"> <Key> <PropertyRef Name="ProductID" /> </Key> <Property Name="ProductID" Type="int" Nullable="false" StoreGeneratedPattern="Identity" /> <Property Name="Name" Type="nvarchar" Nullable="false" MaxLength="50" /> <Property Name="ProductNumber" Type="nvarchar" Nullable="false" MaxLength="25" /> <Property Name="MakeFlag" Type="bit" Nullable="false" /> <Property Name="FinishedGoodsFlag" Type="bit" Nullable="false" /> <Property Name="Color" Type="nvarchar" MaxLength="15" /> <Property Name="SafetyStockLevel" Type="smallint" Nullable="false" /> <Property Name="ReorderPoint" Type="smallint" Nullable="false" /> <Property Name="StandardCost" Type="money" Nullable="false" /> <Property Name="ListPrice" Type="money" Nullable="false" /> <Property Name="Size" Type="nvarchar" MaxLength="5" /> <Property Name="SizeUnitMeasureCode" Type="nchar" MaxLength="3" /> <Property Name="WeightUnitMeasureCode" Type="nchar" MaxLength="3" /> <Property Name="Weight" Type="decimal" Precision="8" Scale="2" /> <Property Name="DaysToManufacture" Type="int" Nullable="false" /> <Property Name="ProductLine" Type="nchar" MaxLength="2" /> <Property Name="Class" Type="nchar" MaxLength="2" /> <Property Name="Style" Type="nchar" MaxLength="2" /> <Property Name="ProductSubcategoryID" Type="int" /> <Property Name="ProductModelID" Type="int" /> <Property Name="SellStartDate" Type="datetime" Nullable="false" /> <Property Name="SellEndDate" Type="datetime" /> <Property Name="DiscontinuedDate" Type="datetime" /> <Property Name="rowguid" Type="uniqueidentifier" Nullable="false" /> <Property Name="ModifiedDate" Type="datetime" Nullable="false" /> </EntityType> </Schema>
Создание концептуальной модели
Добавьте следующий XML-файл в проект и назовите его
AdventureWorks.csdl
. Обратите внимание на следующие моменты.Для двух типов сущности Product и DiscontinuedProduct определяется только один набор сущностей Products.
Тип сущности DiscontinuedProduct является производным, на что указывает атрибут
BaseType
в его определении.Для типов сущности DiscontinuedProduct определяются только ненаследуемые свойства.
Столбец MakeFlag модели хранения (см. файл
AdventureWorks.ssdl
выше) не является свойством базового или производного типа. Значение этого столбца будет использоваться для различения типов в иерархии и сопоставляется как часть условия (см. файлAdventureWorks.msl
ниже).
Примечание Если столбец используется в условии Is Null или Is Not Null, то соответствующее свойство может появиться в типе сущности.
<?xml version="1.0" encoding="utf-8" ?>
<Schema Namespace="AdventureWorksModel" Alias="Self"
xmlns:annotation="https://schemas.microsoft.com/ado/2009/02/edm/annotation"
xmlns="https://schemas.microsoft.com/ado/2008/09/edm">
<EntityContainer Name="AdventureWorksEntities" annotation:LazyLoadingEnabled="true">
<EntitySet Name="Products" EntityType="AdventureWorksModel.Product" />
</EntityContainer>
<EntityType Name="Product">
<Key>
<PropertyRef Name="ProductID" />
</Key>
<Property Type="Int32" Name="ProductID" Nullable="false" />
<Property Type="String" Name="Name" Nullable="false" MaxLength="50"
FixedLength="false" Unicode="true" />
<Property Type="String" Name="ProductNumber" Nullable="false" MaxLength="25"
FixedLength="false" Unicode="true" />
<Property Type="Boolean" Name="FinishedGoodsFlag" Nullable="false" />
<Property Type="String" Name="Color" MaxLength="15" FixedLength="false"
Unicode="true" />
<Property Type="Int16" Name="SafetyStockLevel" Nullable="false" />
<Property Type="Int16" Name="ReorderPoint" Nullable="false" />
<Property Type="Decimal" Name="StandardCost" Nullable="false"
Precision="19" Scale="4" />
<Property Type="Decimal" Name="ListPrice" Nullable="false"
Precision="19" Scale="4" />
<Property Type="String" Name="Size" MaxLength="5" FixedLength="false"
Unicode="true" />
<Property Type="String" Name="SizeUnitMeasureCode" MaxLength="3"
FixedLength="true" Unicode="true" />
<Property Type="String" Name="WeightUnitMeasureCode" MaxLength="3"
FixedLength="true" Unicode="true" />
<Property Type="Decimal" Name="Weight" Precision="8" Scale="2" />
<Property Type="Int32" Name="DaysToManufacture" Nullable="false" />
<Property Type="String" Name="ProductLine" MaxLength="2"
FixedLength="true" Unicode="true" />
<Property Type="String" Name="Class" MaxLength="2" FixedLength="true"
Unicode="true" />
<Property Type="String" Name="Style" MaxLength="2" FixedLength="true"
Unicode="true" />
<Property Type="Int32" Name="ProductSubcategoryID" />
<Property Type="Int32" Name="ProductModelID" />
<Property Type="DateTime" Name="SellStartDate" Nullable="false" />
<Property Type="DateTime" Name="SellEndDate" />
<Property Type="Guid" Name="rowguid" Nullable="false" />
<Property Type="DateTime" Name="ModifiedDate" Nullable="false" />
</EntityType>
<EntityType Name="DiscontinuedProduct" BaseType="AdventureWorksModel.Product" >
<Property Type="DateTime" Name="DiscontinuedDate" />
</EntityType>
</Schema>
Определение сопоставления между концептуальной моделью и моделью хранения
Добавьте следующий XML-файл в проект и назовите его
AdventureWorks.msl
. Обратите внимание на следующие моменты.Сопоставление для типов сущности Product и DiscontinuedProduct определяется в одном элементе EntitySetMapping.
Наследуемые свойства DiscontinuedProduct сопоставляются с соответствующими столбцами в базовых таблицах базы данных.
Синтаксис
IsTypeOf
используется для указания типа производного типа DiscontinuedProduct.Столбец дискриминатора MakeFlag сопоставляется в элементе Condition для каждого типа сущности в иерархии.
<?xml version="1.0" encoding="utf-8" ?> <Mapping Space="C-S" xmlns="https://schemas.microsoft.com/ado/2008/09/mapping/cs"> <EntityContainerMapping StorageEntityContainer="AdventureWorksModelStoreContainer" CdmEntityContainer="AdventureWorksEntities"> <EntitySetMapping Name="Products"> <EntityTypeMapping TypeName="AdventureWorksModel.Product"> <MappingFragment StoreEntitySet="Product"> <ScalarProperty Name="ProductID" ColumnName="ProductID" /> <ScalarProperty Name="ModifiedDate" ColumnName="ModifiedDate" /> <ScalarProperty Name="rowguid" ColumnName="rowguid" /> <ScalarProperty Name="SellEndDate" ColumnName="SellEndDate" /> <ScalarProperty Name="SellStartDate" ColumnName="SellStartDate" /> <ScalarProperty Name="ProductModelID" ColumnName="ProductModelID" /> <ScalarProperty Name="ProductSubcategoryID" ColumnName="ProductSubcategoryID" /> <ScalarProperty Name="Style" ColumnName="Style" /> <ScalarProperty Name="Class" ColumnName="Class" /> <ScalarProperty Name="ProductLine" ColumnName="ProductLine" /> <ScalarProperty Name="DaysToManufacture" ColumnName="DaysToManufacture" /> <ScalarProperty Name="Weight" ColumnName="Weight" /> <ScalarProperty Name="WeightUnitMeasureCode" ColumnName="WeightUnitMeasureCode" /> <ScalarProperty Name="SizeUnitMeasureCode" ColumnName="SizeUnitMeasureCode" /> <ScalarProperty Name="Size" ColumnName="Size" /> <ScalarProperty Name="ListPrice" ColumnName="ListPrice" /> <ScalarProperty Name="StandardCost" ColumnName="StandardCost" /> <ScalarProperty Name="ReorderPoint" ColumnName="ReorderPoint" /> <ScalarProperty Name="SafetyStockLevel" ColumnName="SafetyStockLevel" /> <ScalarProperty Name="Color" ColumnName="Color" /> <ScalarProperty Name="FinishedGoodsFlag" ColumnName="FinishedGoodsFlag" /> <ScalarProperty Name="ProductNumber" ColumnName="ProductNumber" /> <ScalarProperty Name="Name" ColumnName="Name" /> <Condition ColumnName="MakeFlag" Value="0" /> </MappingFragment> </EntityTypeMapping> <EntityTypeMapping TypeName="IsTypeOf(AdventureWorksModel.DiscontinuedProduct)"> <MappingFragment StoreEntitySet="Product"> <ScalarProperty Name="ModifiedDate" ColumnName="ModifiedDate" /> <ScalarProperty Name="rowguid" ColumnName="rowguid" /> <ScalarProperty Name="SellEndDate" ColumnName="SellEndDate" /> <ScalarProperty Name="SellStartDate" ColumnName="SellStartDate" /> <ScalarProperty Name="ProductModelID" ColumnName="ProductModelID" /> <ScalarProperty Name="ProductSubcategoryID" ColumnName="ProductSubcategoryID" /> <ScalarProperty Name="Style" ColumnName="Style" /> <ScalarProperty Name="Class" ColumnName="Class" /> <ScalarProperty Name="ProductLine" ColumnName="ProductLine" /> <ScalarProperty Name="DaysToManufacture" ColumnName="DaysToManufacture" /> <ScalarProperty Name="Weight" ColumnName="Weight" /> <ScalarProperty Name="WeightUnitMeasureCode" ColumnName="WeightUnitMeasureCode" /> <ScalarProperty Name="SizeUnitMeasureCode" ColumnName="SizeUnitMeasureCode" /> <ScalarProperty Name="Size" ColumnName="Size" /> <ScalarProperty Name="ListPrice" ColumnName="ListPrice" /> <ScalarProperty Name="StandardCost" ColumnName="StandardCost" /> <ScalarProperty Name="ReorderPoint" ColumnName="ReorderPoint" /> <ScalarProperty Name="SafetyStockLevel" ColumnName="SafetyStockLevel" /> <ScalarProperty Name="Color" ColumnName="Color" /> <ScalarProperty Name="FinishedGoodsFlag" ColumnName="FinishedGoodsFlag" /> <ScalarProperty Name="ProductNumber" ColumnName="ProductNumber" /> <ScalarProperty Name="Name" ColumnName="Name" /> <ScalarProperty Name="ProductID" ColumnName="ProductID" /> <ScalarProperty Name="DiscontinuedDate" ColumnName="DiscontinuedDate" /> <Condition ColumnName="MakeFlag" Value="1" /> </MappingFragment> </EntityTypeMapping> </EntitySetMapping> </EntityContainerMapping> </Mapping>
См. также
Задачи
Как определить модель с наследованием «одна таблица на тип» (платформа Entity Framework)
Другие ресурсы
Определение расширенных моделей данных (задачи платформы Entity Framework)
Спецификации языка CSDL, SSDL и MSL