继承 (EDM)
在 实体数据模型 (EDM) 中,继承允许派生类型扩展其他类型的功能。
通常,应用程序使用的模型包括许多不同的类型。一些实体类型在模型中表示单独的概念,例如,业务应用程序中的客户和订单。这些数据类型不共享任何成员,但其他一些类型彼此更相似。例如,考虑客户和员工类型。尽管这些类型在模型中代表不同的概念,但具有基本的共性:两者都表示业务关系中涉及的人员,两者都包含用于存储信息(如姓名、地址和电话号码)的属性。
EDM 继承允许从一种类型派生另一种类型。例如,Employee
和 Customer
都可以从 Contact
类型继承。在本例中,Contact
称为基类型,而 Employee
和 Customer
称为派生类型。
继承不必停留在单一级别:一个派生类型可以是另一个实体类型的基类型。例如,Employee
是 Manager
的基类型;Customer
是 PreferredCustomer
的基类型等等。通过此方式,将生成继承层次结构。
与公共语言运行库 (CLR) 类似,EDM 系统也只支持数据类型的单一继承。实体类型只能从一个超类型直接继承属性。
注意 |
---|
由于 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
的实例。当您查询所有员工(基类型)时,您还将获得所有经理(派生类型)。
有关继承的更多信息,请参见如何:通过每种类型一个表继承定义模型和如何:通过每个层次结构一个表继承以定义模型(实体框架)。
继承实现
对于在 EDM 模型上生成的应用程序,必须在存储其数据的数据库表中实现在 CSDL 中定义的继承层次结构。可以通过多种方法在数据库表中设置继承层次结构中的类型的结构。
在所有实现中,基类型和派生类型的键结构必须完全相同。也就是说,如果 Customer
类型派生自 Person
类型,则 Customer
类型和 Person
类型必须指定一个或多个相同的键属性。
在继承的多表实现中,将向多个表中的键属性赋予相同的值,以将派生类型标识为上级类型的实例。
例如,在映射规范中,继承的实现可以使用 EntityTypeMapping 中的 IsTypeOf<T> 指示器来指定 Customer
类型也是基类型 Person 的类型。在概念架构和存储架构中都具有 EntityType 的一个 BaseType 属性,该属性可用于指定派生实体的基类型。
每个层次结构一个表模型
基于每个层次结构一个表模型的继承通过使用同一个数据库表在层次结构中指定多种类型。在此模型中,映射规范中的一个显式条件标识继承层次结构中的类型。
表中包含一个鉴别器列以区分每种类型,而条件引用针对每种类型为此列赋予的值。例如,条件可能指定 EntityType
列的值等于 P
(对于 Person 类型)或 C
(对于 Customer 类型)。
以下映射示例说明 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>
每种类型一个表模型
在基于每种类型一个表模型的继承中,基类型和上级类型存储在一个表中,但会将附加表用于派生类型。特定于派生类型的字段仅出现在表示派生类型的表中。此继承模型中实体的映射涉及多个物理表。表中存在或缺少行可区分层次结构中的类型。将向所有表中的键属性赋予同一个键值。
可以在概念架构和存储架构中使用 EntityType 的 BaseType 属性来指示从基类型的继承。可以使用映射规范中的 IsTypeOf<T> 指示器来指定基类型并消除重复的映射语法。
下面的映射示例演示 Customer
和 Person
类型的两个单独映射。EntityTypeMapping 元素的 TypeName 属性可区分 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>
另请参见
任务
如何:通过每种类型一个表继承以定义模型(实体框架)
如何:通过每个层次结构一个表继承以定义模型(实体框架)