UML软件工程组织

ADO.NET 技术预览:实体数据模型

 

作者:微软  文章来源:微软

 

本页内容
 简介
 基本概念
 EDM 实例
 EDM 基元类型
 EDM 未来发展方向

简介
 “实体数据模型”是一个“实体-关系”数据模型。该模型被大多数的数据库应用程序开发者所熟悉。它已经被成功地使用了30年之久。EDM 中的核心概念是实体和关系。实体是“实体类型”的实例(例如 Customer、Employee),即含有一个键值的充分结构化的记录。一个实体的健值是基于实体类型的一个属性子集而形成的。键值(例如 CustId、EmpId)是一个基础概念,它用作对实体实例的唯一性标识、更新实体实例,并使实体实例之间建立关系成为可能。实体将被归入各“实体集”中(例如,Customers 是 Customer 实例的集合)。关系是“关系类型”的实例,是两个或多个实体类型之间的关联(例如 Employee WorksFor Department)。关系将被归入到各“关系集”中。

EDM 与新的查询语言 eSQL 配合使用,后者为类似于 SQL 的查询语言,旨在实现面向集合的声明式查询以及对实体和关系的更新。EDM 同样也可以与其他查询语言配合使用。

EDM 和 eSQL 结合起来共同表示一种丰富的数据模型和查询语言,目标是使应用程序(例如 CRM 和 ERP)、数据密集型服务(例如“报告服务”、“业务智能”、“复制”和“同步”)以及数据密集型应用程序开发人员可以在更接近于其需要的结构和语义级别对数据进行建模和处理。

本文档是 EDM 的说明书。其目的是提供精确且完整的 EDM 定义。

文档大纲

 本文档包括以下 4 个主要部分。

第 I 部分:介绍核心 EDM 的基本概念

第 II 部分:介绍 EDM 架构(schema)的实例化

第 III 部分:介绍 EDM 实例的管理

第 IV 部分:EDM 基元类型

返回页首

 基本概念
 EDM 概念可分为两种。一种用于定义类型或结构,另一种则用于管理这些类型的实例。

类型

 1.EntityType:EntityType 定义了有关哪类信息必须加以管理的主要数据对象,这些信息包括人物、地点、事件或者与应用程序相关的活动。Entity 是 EntityType 的实例。它具有唯一标识,独立存在,并形成一致性的操作单元。

 2.Property:EntityType 可以拥有一个或多个属性。每个属性的类型可以被指定为以下中的一种: SimpleType、ComplexType 或 RowType。属性可以为单值或多值。

 3.EntityKey:EntityType 的所有实例由其标识属性的值唯一标识。这组标识属性称为 EntityKey。

 4.ComplexType:ComplexType 代表一组相关的信息。与 EntityType 类似,它包含一个或多个属性:SimpleType、ComplexType 或 RowType。但是与 EntityType 不同的是,ComplexType 不与 EntityKey 相关联。

 5.RowType: RowType 是一个匿名类型,在结构上与 ComplexType 非常类似,只是不能参与类型继承。如果两个(匿名)RowType 实例所对应的 RowType 具有相同的编号、顺序和属性类型,则它们是可以被相互比较的。

 6.RelationshipType:EntityType 与数据模型这个名词类似,而 RelationshipType 则是连接这些名词的动词。RelationshipType 描述两个或多个参与的 EntityType。EDM 可支持两种 RelationshipType:Association 和 Containment。Association 类似于一种对等关系,而 Containment 则是一种具有特定成员身份语义的父子关系。

 7.Schema:所有的 EDM 类型都包含在某个命名空间内。Schema 概念定义了描述 EDM 类型范围的命名空间。

实例

  • EntitySet:EntityType 的 EntitySet 包含了其 EntityType 或任何子类型的所有实例。可以为特定的 EntityType 定义多个 EntitySet。
  • 特定关系类型的 RelationshipSet 可以包含该类型的实例。关系实例可以连接参与该 RelationshipSet 的 EntitySet 中所包含的实体实例。RelationshipSet 描述包括 RelationshipType 和 RelationshipType 中所描述的 EntityType 的相应 EntitySet。
  • EntityContainer:所有基于实例的 EDM 概念(例如 EntitySet 和 RelationshipSet)都在 EntityContainer 的范围中定义。用户可以拥有一个或多个 EntityContainer 的实例。EntityContainer 可以引用一个或多个 Schema。

抽象语法
 我们使用基于扩展巴科斯范式 (EBNF) 的表示法来描述用于创建 EDM 概念的语法。使用以下表示法描述抽象语法:

  • 使用“大写-粗体”表示常量、键值或终端
  • 使用“大小写混合的斜体”表示文字
  • 使用“大小写混合的粗体”表示非终端
  • 将默认值加下划线

架构定义语言 (SDL)
 我们使用基于 XML 的数据定义语言根据抽象语法描述 EDM 架构,因此该语言被称为架构定义语言 (SDL)。完整的 SDL 在“错误!未找到引用资源。”部分中介绍。在本文中,我们将使用 SDL 分段说明 EDM 概念。

简单类型
 SimpleType 是由基元类型(primitive Type)和枚举类型(EnumerationType) 组成的基本单位。

基元类型
 EDM 使用抽象类型系统定义其基元类型,例如 String、Boolean、SByte、Int16、Int32、Int64、Byte、UInt16、UInt32、UInt64、Float、Decimal、Xml、Guid 和 DateTime。有关 EDM 基元类型的完整描述,请参阅以下第 0 部分。

枚举类型可定义一组符号化的名称,例如(red、blue、green)或(spring、summer、autumn、winter)。枚举类型的实例拥有一个属于本组的值。下列 SDL 示例说明了枚举类型的定义:

示例 1

1. <EnumerationType Name="Seasons">
2. <EnumerationMember Name="Spring" />
3. <EnumerationMember Name="Summer" />
4. <EnumerationMember Name="Autumn" />
5. <EnumerationMember Name="Winter" />
6. </EnumerationType>

上述代码定义了一个称为“Seasons”的类型。该类型的实例只能显示第 2-5 行指定的 4 个值之一。枚举类型的实例被视为 EDM 简单类型(simple type)。枚举类型的值是无序的,换言之,它们可以参与等同性检查,但不能参与排序操作。

EntityType
 Entity 是 EntityType 的实例。它具有唯一标识,独立存在,并形成一致性的操作单元。直观上,EntityType 在数据模型为一些“顶层”的概念建立模型,例如客户、订单、供应商等(以典型的行业系统为例)。Entity 实例表示 EntityType 的某个特殊实例,例如特定的客户或特定的订单。EntityType 可以是抽象的,也可以是具体的,但前者不能拥有实例。

EntityType 具有名称、由一个或多个属性组成的有效负载(payload)、描述一组属性的 EntityKey 以及可唯一标识实体集中实体实例的一些值。

属性的类型可以是 primitiveType、enumerationType、complexType 或 rowType。有关 PrimitiveType 及其适用的约束面,请参见第 19 页。

EntityKey
 实体类型包含由一个或多个自身属

性组成的实体键值。任何非空且永久不变的 SimpleType 属性均可用作此键值。其中不包括复杂类型和多值属性。但是,实体键值中可以包括 ComplexType 的单值 SimpleType 属性。以下示例说明了由单个 SimpleType 属性组成的键值的规范。

示例 2

1. <EntityType Name="Person" Key="Id">2. <Property Name="Id" Type="String" Nullable="false"/>3. <Property Name="Name" Type="Name"/>4. <Property Name="PhoneNumbers" Multiplicity="*"/>5. </EntityType>

抽象语法
 描述 EntityType 的抽象语法如下所示:

EntityType ::= ENTITYTYPE entityTypeName [BASE entityTypeName]
[ABSTRACT true|false] KEY propertyName [, propertyName]*
{(propertyName PropertyType [PropertyFacet]*) +}

PropertyType ::= ((PrimitiveType [PrimitiveTypeFacets]*)
| (complexOrEnumTypeName) | RowType
PropertyFacet ::= ( [NULLABLE true | false] |
[DEFAULT defaultVal] | [MULTIPLICITY [ 1|*] ] )
PropertyTypeFacet ::= LENGTH|MAXLENGTH|PRECISION|SCALE|UNICODE|COLLATION
| DATETIMEKIND|PRESERVESECONDS
PrimitiveType ::= BINARY | BOOLEAN
|DATETIME|DOUBLE|DECIMAL|FLOAT|GUID|SBYTE|INT16| INT32
| INT64 | BYTE | UINT16 | UINT32 | UINT64 | STRING | XML | MONEY)

属性
 属性可通过为 EntityType(或 ComplexType)关联唯一的名称和类型,来描述它的某个方面。属性描述包含名称、类型和诸如 nullable、default 等一组约束面。属性的类型可以是任何的基元类型、ComplexType 或 RowType。与属性相关的约束面可以分为具体类型和不可知类型。不可知类型的约束面适用于所有的属性,而具体类型的约束面则适用于 EDM 基元类型。下一部分将描述一组不可知类型的约束面的集合。

约束面
 Nullable
 除参与 EntityKey 的属性外,所有属性均可为空。可为空的属性的值可以是 NULL。它是布尔型约束面,默认值为 true。以下所示的示例描述了这个约束面的用法。

示例 3

1. <EntityType Name="Person" Key="EmailID">
2. <Property Name="Name" Type="String" />
3. <Property Name="EmailID" Type="String" Nullable="false"/>
4. <Property Name="Address" Type="AddressType"/>
5. <Property Name="PhoneNumbers" Multiplicity="*" Type="String"/>
6. </EntityType>

EmaillD 属性不能为 NULL,表示“Person”实例具有非 NULL 的电子邮件。还需注意,Nullable 可以用于复杂类型和多值属性。例如,Address 属性可以为 NULL,表示不需要为 Address 属性提供 Address 值。

 Default
 默认约束面可以包含属性值“default”。如果在实例化过程中没有指定明确的值,则属性将获取指定的“default”值。在 EDM v1.0 中,默认的约束面适用于单值 SimpleType 属性。约束面的类型与属性的类型相同,其值可以为该类型的任何常量。

Multiplicity
 多重性的概念描述了属性的基数。实体属性可以为单值或多值。值“1”表示单值属性,“*”表示多值属性,默认值为“1”。多值属性的集合语义是一个无序单位组或多重集,多值属性中的各个项是无序的,且允许拥有重复的值。以下示例描述了该约束面的用法。

示例 4

1. <EntityType Name="Person" Key="EmailID">
2. <Property Name="Name" Type="String" />
3. <Property Name="EmailID" Type="String" Nullable="false"/>
4. <Property Name="PhoneNumbers" Type="String" Multiplicity="*" />
5. </EntityType>

第 4 行描述的 PhoneNumbers 属性是一个多值字符串属性,表示该 PhoneNumbers 可以包含零个或多个字符串值。

ComplexType
 ComplexType 提供了一种使用丰富的(结构化的)有效负载创建属性的机制,如以下示例所示。ComplexType 可以从另一个 ComplexType 派生。其定义包括其名称、可选的基本 ComplexType 和有效负载。ComplexType 的有效负载与 EntityType 的有效负载非常相似,如以下抽象语法中所示。

示例 5

1. <ComplexType Name="AddressType">
2. <Property Name="Street" Type="string" nullable="false"/>
3. <Property Name="City" Type="string"/>
4. <Property Name="State" Type="string" fixedLength="2" nullable="false"/>
5. </ComplexType>
6. <EntityType Name="Customer" Key="CustomerId">
7. <Property Name="CustomerId" Type="String"/>
8. <Property Name="Address" type="AddressType"/>
9. <!--其他属性-->
10. </EntityType>

第 1-5 行描述了 ComplexType 的“AddressType”。第 8 行显示了 ComplexType 属性的定义。

抽象语法
 描述 ComplexType 的抽象语法表示如下所示:

ComplexType ::= COMPLEXTYPE name [BASE complexTypeName]
[ABSTRACT true|false]
{ (propertyName PropertyType PropertyFacet* )* }

RowType
 到目前为止,所介绍的 EDM 类型均为不重要的或有名称的类型。本部分将介绍 EDM 唯一的匿名类型:RowType。该类型与 ComplexType 在结构上非常类似,但它不能拥有名称或者从其他类型派生。RowType 的有效负载与 ComplexType 的有效负载完全相同,如下所示:

示例 6

1. <EntityType Name="Customer" Key="CustomerId">
2. <Property Name="CustomerId" Type="String"/>
3. <Property Name="Address">
4. <RowType>
5. <Property Name="Street" Type="string" nullable="false"/>
6. <Property Name="City" Type="string"/>
7. <Property Name="State" Type="string" fixedLength="2" />
8. </RowType>
9. </Property>
10. <!--其他属性-->
11. </EntityType>

第 4-8 行描述了值为 RowType 类型的 Address 属性的声明。因为 RowType 不具有一个名称可以被属性所引用,因此其必须在属性的范围内定义。

适用于 EDM v1.0 的 SDL(基于 XML 的 DDL)不支持值为 RowType 的属性的声明。但是,eSQL 查询结果可以对属性临时赋予类型为 RowType 的值。

抽象语法
 RowType 的抽象语法表示如下所示:

RowType ::= ROWTYPE { (propertyName PropertyType PropertyFacet* )+ }

类型等同性
 如果指定类型的实例名称可比较,则认为这些实例相似。相同的机制可能不适用于匿名类型。本部分介绍了用于确定两种匿名类型可比性的语义。如果两个 RowType 在结构上相等,即具有相同的编号、顺序和属性类型,则认为它们是可比较的。在比较 RowType 时,属性名称并不重要。

关系类型
 实体类型是数据模型的名词,而关系则是连接这些名词的动词。关系表示两个或多个实体间的连接(即 关系或链接)。关系的示例如下:“客户”下一个或多个“订单”,“订单”包括“订单详细信息”,“产品”由一个或多个“供应商”提供等等。在以上句子中,实体均加上引号,以强调它们之间的关系。关系的概念引自传统的“实体-关系”数据模型,并在 EDM 中用作第一类概念。

在 EDM 中,关系类型是一个抽象的概念,两个具体的关系类型是 Association 和 Containment,稍后会在本部分中介绍。

特征描述
 关系的主要特征是程度、多重性、方向和种类。本部分将更加详细地描述这些术语。

程度
 关系的程度(或数量)是与之相关的 EntityType 的数量。最常用的关系形式是二进制关系,它使两个 EntityType 相关联,而三进制关系则使三个 EntityType 相关联,因此最通用的形式便是 n 进制关系,它可使 n 个 EntityType 相关联。

EDM v1.0 被限制为只支持二进制关系。

多重性
 关系的多重性描述了一个 EntityType 可以与其他 EntityType 的实例相关联的实例的基数或数量。多重性的基本类型为:一对一、一对多和多对多,如下所示:


 图 1. 多重性的关系

一对多是多对多的特例,而一对一则是一对多关系的特例。同样,基数或零(表示它是可选的)可被视为上述关系的特例。实例 0 对多是 1 对多的特例。以下所示的示例说明了关系中多重性的用法。

示例 7

1. <Association Name="CustomerOrder">
2. <End Type="Customer" Multiplicity="1">
3. <End Type="Order" Multiplicity="*">
4. <OnDelete Action="Cascade" />
5. </End>
6. </Association>

“多重性”约束面可定义关系端的基数。在本示例中,我们指定一个 Customer(值为“1”,位于第 2 行)有零个或多个 Order 实例(值为“*”,位于第 3 行)。该约束面的其他值为:

“0..1”– 零个或一个

“1”– 只有一个

“*”– 零个或多个

“1..*”– 一个或多个

“n”– 只有 n 个

“n..m”– 数量介于 n 和 m 之间(包括 n 和 m),其中 n 小于或等于 m。

方向
 EDM v1.0 中的所有关系都是双向的。从概念上说,可以将它们视为两个互为相反的关系。在 EDM 的未来版本中,我们会增加对单向关系的支持。

角色
 双向关系实例可以被视作双向连接的实体实例。为关系端指定的标签或名称被称为“角色”。一个关系中的角色名称是唯一的。

种类
 有许多种不同的关系。EDM v1.0 支持两种关系:Association 和 Containment。EDM 的未来版本中可能增加对其他关系概念的支持,它们可捕获应用程序和服务所需的常见语义模式,例如“合成”、“识别”和“部分-整体”。

操作行为
 对于某种操作而言,将相关实体作为单个单元进行操作将非常有用。本部分将介绍可以在关系类型中指定的各种操作及其相关行为。

操作和动作
 RelationshipType 中的操作语义通过指定所需的操作及其对应的动作来描述。

示例 8

1. <EntityType Name="Order" Key="OrderId">
2. <Property Name="OrderId" Type="String"/>
3. <!--其他属性-->
4. </EntityType>
6. <EntityType Name="Customer" Key="CustomerId">
7. <Property Name="CustomerId" Type="String"/>
8. <!--其他属性-->
9. </EntityType>
10.
11. <Association Name="CustomerOrder">
12. <End Type="Customer" Multiplicity="1">
13. <OnDelete Action="Cascade" />
14. </End>
15. <End Type="Order" Multiplicity="*"/>
16. </Association>

在上述示例中,第 11 行的 <Association> 元素用于定义关系。第 13 行的 <OnDelete> 元素通过指定“CustomerOrder”关联的 OnDelete 操作和 Cascade 动作来描述操作行为。

操作
 OnDelete:此操作可指定用于解析与一个已被删除的实体实例相关的关系实例的动作。为进行说明,我们假设一个关系就像一个连接两个顶点的图形的边界。如果删除其中的一个顶点,则会导致边界无效,此时可从以下选项中选择一种来解决该问题:1) 删除指定的顶点、其他顶点和边界,2) 禁止删除连接的顶点,或者 3) 删除指定的顶点和边界。当参与关系中的实体实例被删除时,将会有一组类似的选项。下个部分将介绍 OnDelete 的可用动作的详细信息。

在 EDM v1.0 中,可以只在关系类型的一端指定 Association 的 OnDelete 操作。

动作

 1.Cascade:该动作会指示操作处理器删除关系实例,并在关系的另一端的实体实例上应用该动作。例如,删除属于 Customer 的所有 Order,如上例所示。

 2.Restrict:对实体实例的操作被限制。例如,在存在未决 Order 时防止删除 Customer。

 3.RemoveAssociation:在 Association 关系的任一端对指定的实体实例进行操作,并删除两个实体实例间的 Association 实例。

Association
 它是最常见、最普通的关系之一。可以在参与的实体类型之间定义对等关系,并在任一端支持任何多重性。可以在关系的任一端指定 OnDelete 操作行为。

association 的一个典型示例是 Customer 和 Order 实体之间的关系。该关系通常具有以下特征:

  • 多重性:每个 Order 只与一个 Customer 相关。每个 Customer 拥有零个或多个 Order。
  • 操作行为: OnDelete Cascade;如果具有一个或多个 OrderLines 的 Order 被删除,则对应的 OrderLines 也会被删除。

SDL 使用 <Association> 元素创建该关系,如下所示:

示例 9

1. <Association Name="CustomerOrder">
2. <End Type="Customer" Multiplicity="1" role="Orders" >
3. <OnDelete Action="Cascade" />
4. </End>
5. <End Type="Order" Multiplicity="*" role="OrderedBy" />
6. </Association>

第 1 行中的 <Association> 元素定义了实体类型 Customer 和 Order 之间的 CustomerOrder 关系。

抽象语法
 描述 Association 关系的抽象语法如下所示:

AssociationType ::= ASSOCIATION associationName
(EndDescription EndDescription)
EndDescription ::= ENTITYTYPE entityTypeName [ROLE roleName]
MULTIPLICITY (0..1 | 1 | * | 1..* | n | n..m) [Operation]*
Operation ::= ONDELETE (CASCADE| RESTRICT | REMOVEASSOCIATION)

Containment
 这是一种具有以下特征的关系:

  • 方向:它是一个双向关系,在关系的各个方向上具有不同的语义。
  • 多重性:该关系为 1 到 0..N,其中一端的基数始终为 1。为方便起见,我们将基数为 1 的端称为父,另一端称为子。
  • 排他性的成员身份限制:子实体类型可以参与多个 Containment 关系,但子实体实例只能是一个 Containment 关系实例的成员。换言之,子实体实例始终只包含在一个父实体实例中。
  • 操作行为:Containment 子实体实例始终存活于其父实体实例的范围内。因此,OnDelete 操作的行为被限制为 Cascade 或 Restrict,默认为 Cascade 。

以下示例显示了 Containment 关系的定义:

示例 10

1. <Containment Name="Parent_Child">
2. <End Type="Parent" role="Parent" />
3. <End Type="Child" Multiplicity="*" role="Children" />
4. </Containment>

第 1 行中的 <Containment> 元素定义了实体类型 Parent 和 Child 之间的父子关系。

抽象语法
 描述 Containment 关系的抽象语法如下所示:

ContainmentType ::= CONTAINMENT containmentName (ParentEnd, ChildEnd)
ParentEnd ::= PARENT entityTypeName [ROLE roleName] [Operation]
ChildEnd ::= CHILD entityTypeName [ROLE roleName]
[ MULTIPLICITY (0..1 | 1 | * | 1..* | n | n..m) ]
Operation ::= ONDELETE (CASCADE | RESTRICT)

导航属性
 导航属性是描述关系端的实体伪属性。标准属性描述了与实体相关的值,而伪属性则描述了关系上的导航路径。例如,假设 Customer 和 Order 实体间存在关系,则 Order 实体类型可以描述导航属性“OrderedBy”,该属性表示与该特定 Order 实例相关的 Customer 实例。

DataType
 导航属性的 datatype 始终为 Ref<T>,并具有与相关的关系端相同的多重性。例如,假设 Customer 和 Order 之间存在 1-n 关系,则 Order 实体中的导航属性“OrderedBy”的类型为 Ref<Customer>。

以下示例描述了“导航”属性的创建:

示例 11

1. <EntityType Name="Customer" Key="CustomerId">
2. ...
3. <NavigationProperty name="Orders" RelationshipType="CustOrderType"
toRole="Orders" />
5.
6. </EntityType>
6.
7. <EntityType Name="Order" Key="OrderId">
8. ...
9. <NavigationProperty name="OrderedBy" fromRole="Order"
RelationshipType="CustomerOrderType" toRole="Customer"/>
11. </EntityType>
12.
13. <Association Name="CustomerOrderType">
14. <End Type="Customer" Multiplicity="1" Role="Customer" />
15. <End Type="Order" Multiplicity="*" Role="Orders" />
16. </Association>
17.
18. <!-- NavigationProperty 的备选语法 -->
19.
20. <NavigationProperty Name="Orders" RelationshipType="CustomerOrderType"
fromRole="Customer" toRole="Orders" />
22.
23. <NavigationProperty Name="OrderedBy"
RelationshipType="CustomerOrderType"
fromRole="Orders" toRole="Customer" />

抽象语法
 描述“导航”属性的抽象语法如下所示:

NavigationProperty::= NAVIGATIONPROPERTY NAME propertyName
RELATIONSHIPTYPE relationshipName [FROMROLE role] TOROLE role

继承
 继承是一种基本的建模概念,允许在“单向”关系中关联不同的类型,从而具备扩展性并重用现有类型。当类型 A 从类型 B 继承时,我们称 B 是 A 的基类型,A 是 B 的子类型或派生类型。派生类型可继承其基类型的所有属性,这些属性称为继承属性。派生类型可以扩展为具有更多属性,这些附加属性称为直接属性。直接属性名称与其继承属性名称相同,这种情况下,直接属性则必须使用 new 修饰符限定。名称冲突不会产生歧义,因为在访问名称时会根据实例类型将其解析为直接属性或继承属性。所有有效的派生类型实例始终都是有效的基类型实例,并且可以代替父实例。

EDM ComplexType 只能从其他的 ComplexType 继承;同样,EntityType 只能从其他的 EntityType 继承。EDM v1.0 不支持 RelationshipType 的继承。

派生实体类型始终从其不可更改的基类型继承其键值的定义。下图显示了实体类型的继承示例。


 图 2. 继承和类型层次结构

以下的 SDL 示例显示了从“ContactType”派生的 EntityType“CustomerType”。

示例 12

1. <EntityType Name="ContactType" Key="Id">
2. <Property Name="Id" Type="String"/>
3. <!--其他属性-->
4. </EntityType>
5. <EntityType Name="CustomerType" baseType="ContactType" >
6. <Property Name="CompanyName" Type="String" Nullable="false" />
7. </EntityType>

Schema
 一般而言,类型和数据模型系统允许所创建的类型在物理上位于库或文件中,或者逻辑上位于命名空间中。这与 SQL、CLR 和 XSD 中命名空间的概念类似。所有的类型都位于某个命名空间中。Schema 是允许创建命名空间的 EDM 结构。

命名空间中的内容可由一个或多个 schema 实例定义。同一个命名空间中的类型名称必须唯一。例如,在同一个命名空间中,EntityType 不能具有与 ComplexType 相同的名称。命名空间是类型全限定名称的组成部分。以下示例说明了 Schema 结构的使用方法。

示例 13

1. <Schema Namespace="MyCompany.LOBSchema">
2. <EntityType Name="Customer" Key="CustomerId">
3. ...
4. </EntityType>
5. <EntityType Name="Order" Key="OrderId">
6. ...
7. </EntityType>
8. <ComplexType Name="Address">
9. ...
10. </ComplexType>
11. </Schema>

该示例显示了在名为 MyCompany.LOBSchema 的 schema 中定义了 Customer 和 Order。注意,该 schema 中定义的每个名称还具有一个全限定名称,例如 MyCompany.LOBSchema.Customer。

Schema 可使用 Using 子句导入其他 Schema 或命名空间,从而引用它们的内容。导入的命名空间可以与别名相关联,然后可以使用该别名引用其类型或可通过指定全限定名称直接使用类型。下面的 SDL 示例说明了这些概念:

示例 14

1. <Schema Namespace="MyCompany.MySchema">
2. <Using Namespace="YourCompany.YourSchema"/>
3. <Using Namespace="AnotherCompany.AnotherSchema" Alias="Another"/>
4. <ComplexType Name="Type1" BaseType="YourType">
5. ...
6. </ComplexType>
7. <EntityType Name="Type2" BaseType="Another.AnotherType">
8. ...
9. </EntityType>
10. <EntityType Name="Type3" Key="...">
11. <Property Name="Type3Prop1"
Type="YourCompany.YourSchema.YourType" />
13. ...
14. </EntityType>
15. </Schema>

第 2 行导入了名为 YourCompany.YourSchema 的命名空间。YourType 在该 schema 中定义,并可在没有限定的情况下使用(因为它在所有可见的命名空间中是唯一的),如第 4 行所示。还可以为导入的命名空间定义别名,如第 3 行所示。可使用别名来限定该命名空间中的类型,从而引用它们,如第 8 行所示。别名不能与现有命名空间的名称相同。

抽象语法
 描述 Schema 的抽象语法如下所示:

Schema ::= SCHEMA namespace [USING namespace [ALIAS aliasName]]*
{(EntityType | ComplexType | RelationshipType | EnumerationType)*}

EDM 类型分类
 到目前为止,我们已经见识了 EDM 中提供的各种类型。在本节中,我们对 EDM 类型系统中的类型进行了恰当的分类。具体如下图所示


 图 3. EDM 类型系统

返回页首

 EDM 实例
 EDM 提供了定义类型以及管理这些类型的实例的概念。EDM 中的顶层实例被称为实体,属于 EntityType 类型,并且最多属于一个 EntitySet。其他一些类型,例如关系类型,在关系集上下文中拥有实例,而 ComplexType、RowType 和 SimpleType 则在实体实例的属性上下文中拥有实例。本节介绍了用于管理实例的结构。

EntitySet
 实体类型 ET 的 EntitySet ES 可以包含 ET 以及任何子类型的实例。可以为特定的实体类型定义多个实体集。EntitySet 包含的任何实体实例均需满足以下三个条件:

实体实例类型与 EntitySet 的类型或其任何子类型相同。

实体实例的键值可以在 EntitySet 中唯一标识该实例。

实体实例不是任何其他 EntitySet 的成员

以下 SDL 示例显示了 EntitySet 的声明

示例 15

1. <EntitySet Name="CustomerSet" EntityType="CustomerType"/>

本示例显示了创建一个 EntitySet,其命名为 CustomerSet,EntityType 为 CustomerType。

抽象语法
 描述 EntitySet 的抽象语法如下所示:

EntitySet ::= ENTITYSET entitySetName ENTITYTYPE entityTypeName

RelationshipSet
 RelationshipSet 中包含指定 RelationshipType 的关系实例。关系实例可连接两个或多个属于 EntitySet 的实体实例,这些 EntitySet 与 RelationshipSet 相关联。RelationshipSet 描述中含有可包含 EntityType 实例的 EntitySet,这些 EntityType 与 RelationshipType 端相关联。

更正式的描述如下:假设 EntityType ET1 和 ET2 上有一个 RelationshipType RT,且 RT、EntitySet ES1 和 EntitySet ES2 的 RelationshipSet RS 有 RT 的实例,这些实例连接 ES1 和 ES2 中的实体实例。

RelationshipType 和 RelationshipSet 是抽象概念。对于每个 RelationshipType 的具体实现,存在一个与之对应的具体的 RelationshipSet。例如,AssociationType 是一个具体的 RelationshipType,AssociationSet 是一个具体的 RelationshipSet。本节介绍了 AssociationSet 和 ContainmentSet,EDM v1.0 支持这两个具体的 RelationshipSet。

EDM v1.0 最多允许每个 EntitySet 具有一个 RelationshipType,每个 RelationshipType 具有一个 RelationshipSet。

AssociationSet
 AssociationSet 中包含指定 AssociationType 的关系实例。AssociationType 可指定两个端点的 EntityType,而 AssociationSet 可指定与这些 EntityType 对应的 EntitySet。AssociationSet 中的关联实例与属于这些 EntitySet 的实体实例相关。

下列 SDL 示例说明了 AssociaitonSet 的用法

示例 16

1. <EntityType Name="Customer" Key="CustomerId">
2. ...
3. </EntityType>
4. <EntityType Name="Order" Key="OrderId">
5. ...
6. </EntityType>
7. <Association Name="CustomerOrderType">
8. <End Type="Customer" Multiplicity="1" Role="OrderedBy" />
9. <End Type="Order" Multiplicity="*" Role="Orders" />
10. </Association>
11.
12. <EntitySet Name="CustomerSet" EntityType="Customer"/>
13.
14. <EntitySet Name="OrderSet" EntityType="Order"/>
15.
16. <AssociationSet Name="CustomerOrderSet"
Association="CustomerOrderType">
17. <End EntitySet="CustomerSet"/>
18. <End EntitySet="OrderSet"/>
19. </AssociationSet >

第 1 – 6 行描述了 EntityType“Customer”和“Order”的创建。第 7 行定义了 AssociationType“CustomerOrderType”。第 12 – 14 行描述了 EntitySet“CustomerSet”和“OrderSet”的创建。第 16 行中的 <AssociationSet> 元素定义了上面第 7 行定义的“CustomerOrderType”类型中名为“CustomerOrderSet”的 AssociationSet。第 17 和 18 行指定了对应于 AssociationType 端 EntityType 的 EntitySet。关联实例位于 CustomerOrderSet 中,并连接 CustomerSet 和 OrderSet 中的实例。

抽象语法
 描述 AssociationSet 的抽象语法如下所示:

AssociationSet ::= ASSOCIATIONSET assocSetName
TYPE assocType {EndDescription EndDescription}
EndDescription ::= END ENTITYSET entitySetName

ContainmentSet
 ContainmentSet 中包含指定 ContainmentType 的关系实例。ContainmentType 指定父端和子端的 EntityTypes,而 ContainmentSet 指定含有这些 EntityTypes 实例的 EntitySets。ContainmentSet 中的 Containment 实例与属于这些 EntitySet 的实体实例相关。

下列 SDL 示例说明了 ContainmentSet 的用法

示例 17

1. <EntityType Name="Organization" Key="Id">
2. ...
3. </EntityType>
4. <EntityType Name="Department" Key="Id">
5. ...
6. </EntityType>
7.
8. <Containment Name="OrgHasDeptType">
9. <Parent Type="Organization" Name="HasDept" />
10. <Child Type="Department" Multiplicity="*" Name="ContainedBy" />
11. </Containment>
12. <Containment Name="DeptHasDeptType">
13. <Parent Type="Department" />
14. <Child Type="Department" Multiplicity="*" Name="ContainedBy" />
15. </Containment>
16.
17. <EntitySet Name="OrganizationSet" EntityType="Organization"/>
18. <EntitySet Name="DepartmentSet" EntityType="Department"/>
19.
20. <ContainmentSet Name="OrgHasDeptSet" Containment="OrgHasDeptType">
21. <Parent EntitySet="OrganizationSet" />
22. <Child EntitySet="DepartmentSet" />
23. </ContainmentSet>
24. <ContainmentSet Name="DeptHasDeptSet" Containment="DeptHasDeptType">
25. <Parent EntitySet="DepartmentSet" />
26. <Child EntitySet="DepartmentSet" />
27. </ContainmentSet>

第 1 – 6 行描述了 EntityTypes“Organization”和“Department”的创建。第 8 – 16 行定义了 ContainmentTypes“OrgHasDeptType”和“DeptHasDeptType”。第 17 - 19 行描述了 EntitySet“OrganizationSet”和“DepartmentSet”的创建。第 20 行上的 <ContainmentSet> 元素定义上述第 8 行定义的“OrgHasDeptType”类型中名为“OrgHasDeptSet”的 ContainmentSet。第 21 和 22 行分别指定与 ContainmentType 中父子 EntityType 相对应的两个 EntitySet。第 25 – 28 行描述相同 EntitySet 中不同 ContainmentType 的另一个 ContainmentSet “DeptHasDeptSet”。

抽象语法
 描述 ContainmentSet 的抽象语法如下所示:

ContainmentSet ::= CONTAINMENTSET name TYPE containmentTypeName
{ Parent Child }
Parent ::= PARENT entitySetName
Child ::= CHILD entitySetName

实体容器
 所有的 EDM 类型在命名空间范围内进行定义,命名空间使用 Schema 结构予以创建。同样,所有的 EDM 实例包含在由 EntityContainer 实例范围内定义的 EntitySet 和 RelationshipSets 之中。EntityContainer 实例使用 EntityContainer 结构创建而成。其中包含 EntitySets 和 RelationshipSets 的描述,它们可以使用一个或多个命名空间定义的类型。RelationshipSet 只能包含位于其自身 EntityContainer 中 EntitySets。

下列 SDL 示例展示了如何创建 EntityContainer 实例。

示例 18

1. <Schema Namespace="MyCompany.EntityTypes">
2. <EntityType Name="Order" Key="OrderId">
3. <Property Name="OrderId" Type="String"/>
4. <!--其他属性-->
5. </EntityType>
6. <EntityType Name="Customer" Key="CustomerId">
7. <Property Name="CustomerId" Type="String"/>
8. <!--其他属性-->
9. </EntityType>
10. </Schema>
11. <Schema Namespace="MyCompany.RelationshipTypes">
12. <Using Namespace="MyCompany.EntityTypes" Alias="basicTypes"/>
13.
14. <Association Name="CustomerOrder">
15. <End Type="basicTypes.Customer" Multiplicity="1" />
16. <End Type="basicTypes.Order" Multiplicity="*" />
17. </Association>
18. </Schema>
19. <EntityContainer name="ContainerOne">
20. <Using Namespace="MyCompany.EntityTypes" Alias="basicTypes"/>
21. <Using Namespace="MyCompany.RelationshipTypes" Alias="relnTypes"/>
22.
23. <EntitySet Name="CustomerSet" EntityType="basicTypes.Customer"/>
24. <EntitySet Name="OrderSet" EntityType="basicTypes.Order"/>
25.
26. <AssociationSet Name="CustOrdSet"
Association="relnTypes.CustomerOrder">
27. <End EntitySet="CustomerSet" Role="Orders"/>
28. <End EntitySet="OrderSet" Role="OrderedBy"/>
29. </AssociaitonSet >
30. </EntityContainer>

抽象语法
 描述 EntityContainer 的抽象语法如下所示:

ENTITYCONTAINER ::= ENTITYCONTAINER CONTAINERNAME
[USING NAMESPACE [ALIAS ALIASNAME] ]*
{ (EntitySet | AssociationSet | ContainmentSet) * }

返回页首

 EDM 基元类型

 基元类型是系统提供的原子内置类型。EDM 使用抽象类型系统来定义其基元类型,如整型、字符串型、布尔型等等。EDM 会提示从这些类型到其他规范类型系统(例如能托管或实例化 EDM 实例的 CLR、SQL 和 XSD)中相应基元类型的默认映射。EDM 不会尝试指定抽象简单类型的运算或转换语义。这些类型的具体实例将会表现托管类型系统所规定的语义。

本部分所述的数据类型基于已知的抽象概念如整型和浮点型。为实现跨多类型系统的互操作性和优化的表现,这些类型支持允许对类型本身进行调整的约束面。本部分介绍所有 EDM 基元类型。

基元类型
 Binary

二进制 (Binary) 数据类型用于表示固定或可变长度的二进制数据。

约束面(Facets)

适用于该类型的 EDM 简单类型约束面是 fixedLength 和 maxLength。这两者之间互相排斥,此类型的每一声明只能指定其中一项。

fixedLength
 fixedLength facet 是正整数,其值范围为 1 至 2^31。二进制数据类型的实例大小始终等于指定的长度值。

maxLength
 maxLength facet 是正整数,其值范围为 1 至 2^31。所声明二进制数据类型的最大值由 maxLength 约束面指定。

Boolean
 布尔型 (Boolean) 数据类型用于表示二进制值表示的逻辑的数学概念。没有适用于此类型的约束面。

DateTime
 日期时间型 (DateTime) 代表数据和时间,其值范围从公元 1 年 1 月 1 日午夜 12:00:00 至公元 1999 年 12 月 31 日夜间 11:59:59。最大时间粒度以毫秒为单位。

约束面

日期时间型有两个可选约束面,一个用于指定时间粒度,另外一个用于关联时区信息。

preserveSeconds
 preserveSeconds 约束面是布尔型约束面,默认值为 true。如果 preserveSeconds 为 true,则日期时间型值将会保留指定时间的秒和毫秒,否则将会忽略。

dateTimeKind
 可以使用“协调世界时”(UTC) 标准、本地时区或不可知时区来表示日期时间型值。dateTimeKind 约束面可用于指定所需的时区特征。它属于 EDM 枚举型,其值为 UTC、Local 和 Unspecified,默认值为 Unspecified。

Decimal
 Decimal 类型代表具有固定精度和小数位数的数值。所需的精度和小数位数可通过可选的精度和小数位数约束面来指定。此类型可以描述范围在负 10^38 + 1 至正 10^38 -1 之间的数值。

约束面
 precision

此为正整数,用于指定十进制小数型数值中小数点左右两侧的最大位数。precision 值的范围在 1 - 38 之间。默认精度为 18。

scale

此为正整数,用于指定此类型实例十进制小数点右侧的最大位数。scale 值的范围在 0 至指定的 precision 值之间。默认小数位数为 0。

Float

浮点类型 (float) 代表 7 位精度的浮点数,可用于描述范围约在 ± 1.18e -38 至 ± 3.40e +38 之间的数值。

Double

双精度 (double) 类型代表 15 位精度的浮点数,可用于描述范围约在 ± 2.23e -308 至 ± 1.79e +308 之间的数值。

Guid

此 Guid 类型代表 16 个字节(128 位)的唯一标识符值。

SByte

sbyte 类型代表签名的 8 位整数值

Int16

int16 类型代表签名的 16 位整数值

Int32

int32 类型代表签名的 32 位整数值

Int64

int64 类型代表签名的 64 位整数值

Byte

byte 类型代表未签名的 8 位整数值

UInt16

uint16 类型代表未签名的 16 位整数值

UInt32

uint32 类型代表未签名的 32 位整数值

UInt64

uint64 类型代表未签名的 64 位整数值

String

字符串 (string) 类型代表固定或可变长度的字符数据。适用于字符串类型的 EDM 简单类型约束面如下所述。

约束面
 适用于该类型的 EDM 简单类型约束面是 unicode、length 和 maxLength。length 和 maxLength 约束面之间相互排斥,两者只能指定其一。其他约束面 Unicode 和 collation 为可选项。

unicode

unicode 约束面为布尔值。该值设为 true 时,表示字符串类型实例存储 unicode 字符,否则会存储标准的 ASCII 编码。此约束面的默认值为 true。

注:字符串数据类型不支持指定 unicode 的种类,将其留给托管 EDM 的具体类型系统以选择适当的 Unicode 风格。

fixedLength

fixedLength 约束面指定字符串类型实例的长度。如果 unicode 为 true,则长度范围是 1 - 2^30,否则为 1 - 2^31。

maxLength

maxLength 约束面指定字符串类型实例的最大长度。如果 unicode 为 true,则 maxLength 的范围是 1 - 2^30,否则为 1 - 2^31。

collation

collation 约束面为字符串值,用于指定排序顺序(或分类序列),以对字符串值执行比较和排序操作。

Money

money 类型代表具有指定精度和固定 4 位小数的货币数据。precision 约束面可用于指定所需的精度值。此类型可描述介于负 2^63 至 2^63 -1 之间的任意数值,准确度达到千分之十货币单位。

约束面
 precision

此为正整数,指定用于存储 money 类型实例的字节数;亦可表示 money 类型实例的精度。此类型的 precision 值可为 4 或 8,默认值为 8。

Xml

xml 类型是不同于其他 EDM 简单类型的丰富类型。简单类型本质上由原子单位构成的。而此类型的实例可包含格式完整的 XML 或有效的 XML 数据。下面描述的约束面允许更大程度地控制 xml 类型实例可以包含的 XML 数据种类。

约束面
 xmlFragment [Post EDM v1.0]

xmlFragment 为布尔型,如果设为 true,则表示 xml 类型实例可以包含片段。如果设为 false,则表示此为文档,不能包含片段。此为可选约束面,其默认值为 true。

xmlSchema [Post EDM v1.0]

xml 数据在默认情况下是非类型化的,不受任何 xml 架构的约束。xmlSchema 约束面描述用以约束此类型实例所包含 xml 数据的 xml 架构元素。

此为可选约束面,其默认值为 xsd:any。

适用约束面
 EDM 定义多种简单类型约束面,来定制简单类型的特定实例。约束面有很多种,但并非所有的都适用于每一种简单类型。下表列出了各种简单类型及其适用的约束面。


 图 4. 简单类型及其适用的约束面

EDM 和规范类型系统

 就简单类型而言,EDM 类似于 SQL 标量类型系统或者 .NET Framework 的公共类型系统 (CTS)。EDM 使用抽象类型系统来定义其可映射到具体规范类型系统的简单类型。下表描述了建议实现的 EDM 简单类型与其他类型系统的映射。这样,即可通过至少一种方法将 EDM 类型映射到这些规范类型系统,从而使数据在这些类型系统间相互传递时保持相应的保真度。

Binary [ML ::= 1 到 8000 || L ::= 1 - 8000 || ( ML>8000 || L>8000)]

其中: L=FixedLength,ML = MaxLength;Fixedlength 和 maxLength 约束面互相排斥。

Boolean


 DateTime [Kind ::= Unspecified | UTC | Local, preserveSeconds ::= Bool]


 注:

1.Sql Server 正准备扩展其 DateTime 类型以支持像 Kind 之类的约束面,我们需要与扩展的 DateTime 保持一致

 2.CLR 支持 Kind 约束面 – 语义相同

 3.XSD 不支持类型级别上的 TimeZone 约束面。但是,XML 序列化提供 TimeZone 信息的编码/解码机制。

Decimal [precision ::= positiveInteger<x, scale::= positiveInteger<y]


 注:

CLR 不支持显式 precision 和 scale 约束面。

如果 precision <=28,CLR 可以映射到 System.Decimal。或者如果必须支持 precision>28,则 EDM Decimal 可以映射到 CLR SqlDecimal。

Guid


 注 SqlServer 和 CLR 都支持 16 字节 GUID

不同种类的整数


 注:

  • 为简便起见,我们选择在一个整数部分下代表所有整数类型。
  • 为便于说明 XSD 类型,我们使用 UByte 表示 UnsignedByte。使用 UInt 表示 UnsignedInt 等等。

Float 和 Double


 String [maxLength ::= 1 - 2^31, length ::= 1 - 2^31, unicode::=Bool]


 其中: L=FixedLength,ML = MaxLength

注 我们需要进一步指定 1) maxLength 的默认值;2) 是否添加 Collation 的其他约束面并指定默认值?

Xml


 Money [precision = 4 || 8]


 返回页首

 EDM 未来发展方向

 本部分介绍 EDM 未来版本需要考虑的几个概念。

条件性关联
 标准关系实例将两个或多个由其键属性值识别的实体实例连接在一起。标准关系类型被隐式地限定去引用实体类型的键属性;它不被允许在任意属性上关联实体类型。而条件性关联关系则允许两个实体类型在任何类型兼容的属性集上相关联。标准关联实例必须显式地创建,而条件关联实例则隐式地创建;它们都是指定条件的函数,隐式地将符合条件的实体实例连接在一起。

示例 1

1.<Association Name="RecentOrders">
2 <End Type="CustomerType" role="Customer" />
3. <End Type="OrderType" role="Orders" />
4. <Condition>
5. Customer.CustomerId = Orders.CustomerId
6. </Condition>
7. </Association>

第四行的 <Condition> 元素描述了限定关联实例必须满足的条件。

关系
 EDM v1.0 Relationships 允许两个 EntityType 之间建立关系,但是 Relationship 本身不能具有任何属性。尽管大多数情况下这样是可以的,但仍有许多情况下,一个关系能够拥有属性并能够关联两个以上 EntityType 会使它变的更加直观。本部分介绍即将对 EDM v1.0 Relationships 进行的扩展。

带有效负载的关系
 关系概念使得捕获实体间的关系成为可能。当前不允许关系本身带有任何属性这一约束条件有着很大的局限性,我们要放开这一限制,允许其有零个或多个属性。这些都是关系属性,带属性的关系仍然是关系,可用于所有适用标准关系的地方。具体来说,这并不意味着带属性的关系可以称为另一个其他关系的终结点,关系的终结点始终是实体。我们使用 Association 关系来进一步描述带属性的关系这一概念。

SDL 使用 <Association> 元素创建该关系,如下所示:

示例 2

1. <Association Name="OfficeHistory">
2. <End Type="Employee" Multiplicity="*" role="Employees" />
3. <End Type="Office" Multiplicity="1" role="Office" />
4. <Property Name="MoveInDate" Type="DateTime" />
5. <Property Name="MoveOutDate" Type="DateTime" />
6. </Association>

第一行中的 <Association> 元素定义了实体类型 Employee 和 Office 之间的 OfficeHistory 关系。

多元关系
大多数情况下,二进制关系足以捕获用户域模型中的关系,但在许多情况下,使用多元关系能够更好地描述域模型。多元关系可以有两个以上的端点(或超过两个端点的程度)。我们使用 Association 关系来进一步描述多元关系这一概念。

示例 3

1. <Association Name="Annotations">
2. <End Type="Document" Multiplicity="1" role="Document" />
3. <End Type="Contacts" Multiplicity="*" role="Contact" />
4. <End Type="Comments" Multiplicity="*" role="Comment" />
5. </Association>

第一行中的 <Association> 元素定义了实体类型 Document、Contact 和 Comment 之间的 Annotations 关系。

关系继承
 EDM 支持 EntityType 和 ComplexTypes 继承,但是不支持关系继承。未来将考虑支持这样情况下的继承:派生关系可以选择添加更多的属性,或在关系端限制实体成为特定类型,或者两者皆有。

动态实体扩展性
 一个众所周知的扩展机制就是通过继承这一概念。EDM 支持 EntityTypes 和 ComplexTypes 的继承。此类扩展允许创建扩展自其他类型的新类型,这是一种静态的扩展性。另一种扩展性是动态扩展性,即允许将额外的结构化数据与任何元素实例相关联。正在考虑的实体扩展性机制如下:

  • 静态扩展性
  • 新的 EntityType 可以从任何现有的 EntityType 继承下来
  • 动态扩展性
  • 一组新的不可查询名称-值属性包可与任何 EntityType 相关联
  • 一组新的可查询名称-值属性包可与 EntityType 相关联
  • 一组新的可查询强类型可查询属性可与 EntityType 相关联
  • 上述三项均可与适用于单个 EntitySet 的 EntityType 相关联
  • 一组新的可查询强类型属性可与特定的实体实例相关联。这些属性也可以有选择性地是不可查询或非类型化的字符串。

递归 ComplexType

 ComplexType CT 的属性 P 可以是 ComplexType CT 类型。

  • 2006 Microsoft Corporation 版权所有。保留所有权利。使用规定。

 


版权所有:UML软件工程组织