复杂类型
WCF RIA Services 中的复杂类型支持提供一个方法以便将一组实体属性封装到单个(复杂)属性中。可以在某一实体包含相关属性的特定子集时,使用这些类型简化该实体。复杂类型也可由共享该相同属性的子集的其他(不同)实体重复使用。复杂类型的一个常见示例就是 Address
,它将指定某一地址所需的实体属性集合在一起。例如,此类 Address
类型中的属性集可以包括 StreetAddress
、City
、StateProvince
、PostalCode
和 Country
实体属性。这一复杂类型可以由 Customer
和 Contact
实体使用,只要它们分别共享此属性集。因此,一旦定义后,该自定义 Address
类型可以在其他实体中用作实体属性本身。
一个复杂类型就是用于对实体类型或其他复杂实体定义丰富的结构化属性的模板,因为一个复杂类型可以包含也属于某一复杂类型的属性。一个复杂类型必须指定在其命名空间中唯一的名称并且可以包含采用一个或多个属性形式的数据。复杂类型只能作为实体类型或其他复杂类型上的属性存在,因为它们没有标识,因此无法独立存在。复杂类型是真实类型,因此可以实例化并在代码中使用,但它们不能被直接查询或持久化到某一数据库,但实体类型是可以这样做的。复杂类型也不同于实体,因为它们不能参与关联。因此,不能对复杂类型定义导航属性,但对实体类型则可以。
已在 WCF RIA Services V1.0 SP1 中添加了对非实体复杂类型的支持。具体来说,为从 ComplexObject 基类派生的复杂类型的代码生成提供支持。对生成客户端代理的支持在丰富性上与对 RIA Services 中的实体一样。还提供对实体的元数据支持,例如深度验证、更改跟踪、编辑会话以及对复杂类型参数的支持。这意味着,Address
之类的自定义类型现在不仅可用作实体属性,还可用作域服务方法的参数或返回值。
定义和表示复杂类型
本节介绍如何使用实体数据模型 (EDM) 设计器将一组实体属性从实体类型封装到复杂类型中。实体数据模型 (EDM) 使用一种称为概念架构定义语言 (CSDL) 的域特定语言 (DSL) 来定义概念模型。将检查 CSDL 中隐藏在设计器背后的复杂类型的 XML 表示形式。
本主题假定您已完成了演练:创建 RIA Services 解决方案,或掌握了等同知识并在手头有一个现成的 RIA Services 解决方案。
使用设计器创建复杂类型
打开通过演练演练:创建 RIA Services 解决方案获得的 RIAServicesExample 解决方案,并且在实体框架设计器中打开 AdventureWorksModel.edmx 文件(默认打开该文件)。
从
Address
实体中选择以下属性:AddressLine1
、AddressLine2
、City
、StateProvince
、CountryRegion
和PostalCode
。右击这些属性之一并且选择**“重构为新的复杂类型”。这将导致“模型浏览器”打开,其中,刚创建的复杂类型(默认命名为 ComplexType1)出现在 AdventureWorksModel.edmx 的 ComplexTypes 文件夹中。在“模型浏览器”中指定的名称实际为新的 ComplexProperty 的类型。现在,在“模型浏览器”**中可以看到由这个新的复杂属性封装的子属性。
在**“模型浏览器”中选择
ComplexType1
并且将其更改为MailAddress
。此类型现在是新的 ComplexProperty 的类型,可通过在Address
实体中选择 ComplexProperty 并且注意“属性”**窗口中的类型进行验证。在**“属性”窗口中,将新的
MailAddress
类型的“名称”**更改为 MailAddress。请注意,这个新名称现在也显示在设计器中。在设计器中选择
MailAddress
,右击并选择**“表映射”以便访问“映射详细信息”**表。该表指示如何将属性映射到数据库的表列。
复杂类型的 XML 表示形式
RIA Services 使用概念架构定义语言 (CSDL) 来指定数据模型。概念架构定义语言是一种基于 XML 的语言,它描述构成数据驱动应用程序的概念模型的实体、关系和函数。在 XML 的 CSDL 部分中指定新的 MailAddress
类型。
若要在**“解决方案资源管理器”中访问这一所选 AdventureWorksModel.edmx,请右击并选择“打开方式”,然后选择“XML(文本)编辑器”。Visual Studio 2010 将需要关闭数据模型的“设计”视图以便打开 XML 表示形式,因此选择“是”**以便允许这样做。请注意,这个新的 MailAddress
属性是在元素 <EntityType Name=”Address”>
内指定的:
<Property Name="MailAddress" Type="AdventureWorksLTModel.MailAddress" Nullable="false" />
该 MailAddress
属性在定义关联的部分之下的自己的元素中定义。
<ComplexType Name="MailAddress">
<Property Type="String" Name="AddressLine1" Nullable="false" MaxLength="60" FixedLength="false" Unicode="true" />
<Property Type="String" Name="AddressLine2" MaxLength="60" FixedLength="false" Unicode="true" />
<Property Type="String" Name="City" Nullable="false" MaxLength="30" FixedLength="false" Unicode="true" />
<Property Type="String" Name="StateProvince" Nullable="false" MaxLength="50" FixedLength="false" Unicode="true" />
<Property Type="String" Name="CountryRegion" Nullable="false" MaxLength="50" FixedLength="false" Unicode="true" />
<Property Type="String" Name="PostalCode" Nullable="false" MaxLength="15" FixedLength="false" Unicode="true" />
</ComplexType>
请注意,在 <ComplexType>
元素内没有 <Key>
元素,因为存在 <EntityType>
元素。
在其他实体内重复使用复杂类型
如果我们具有一个 Manufacturer
实体类型,该类型包含一组相同的地址属性,则我们可以将它们封装在复杂 MailAddress
类型中。像您创建复杂类型一样使用**“重构为新的复杂类型”,然后在“属性”窗口中更改该类型和名称。这些字段将指回其各自的实体。例如,Address
实体的 MailAddress
的 City
字段将映射到 Address.City
,而此字段将映射到 Manufacturer
实体类型的 Manufacturer.City
。使用“映射详细信息”**表以便确保属性映射回数据库中正确的列。