Complex Types
[WCF RIA Services Version 1 Service Pack 2 is compatible with either .NET framework 4 or .NET Framework 4.5, and with either Silverlight 4 or Silverlight 5.]
Complex type support in WCF RIA Services provides a way to encapsulate a set of entity properties into a single (complex) property. These types can be used to simplify an entity when it contains a particular subset of related properties. Complex types can also be reused by another (different) entity that shares that same subset of properties. A common example of a complex type is an Address, which gathers together the entity properties required to specify an address. The set of properties in such an Address type could include, for example, the StreetAddress, City, StateProvince, PostalCode, and Country entity properties. This complex type could be used by both Customer and Contact entities provided that they each shared this property set. So once defined, the custom Address type can be used as an entity property itself in other entities.
A complex type is a template for defining rich, structured properties on entity types or on other complex entities, as a complex type can contain properties that are also of a complex type. A complex type must specify a name that is unique within their namespace and (optionally) contains data in the form of one or more properties. Complex types can only exist as properties on entity types or other complex types as they do not have identities and so cannot exist independently. Complex types are genuine types and so can be instantiated and used in code, but they cannot be queried directly or persisted to a database as can an entity type. Complex types also differ from entities in that they cannot participate in an association. So navigation properties cannot be defined on complex types as they are on entity types.
Support for non-entity complex types has been added in WCF RIA Services V1.0 SP1. Specifically, support is provided for the codegen of complex types that derive from the ComplexObject base class. The support for generating client proxies is as rich as it is for entities in RIA Services. Metadata support on par with entities is also provided, as is deep validation, change tracking, edit sessions, and support for parameters of a complex type. This means that custom types, such as Address, can now be used not only as entity properties but also as parameters or as return values for domain service methods.
Defining and Representing a Complex Type
This section describes how to use the Entity Data Model (EDM) Designer to encapsulate a set of entity properties from an entity type into a complex type. The Entity Data Model (EDM) uses a domain-specific language (DSL) called conceptual schema definition language (CSDL) to define conceptual models. The XML representation of the complex type in CSDL that is behind the Designer is examined.
This topic assumes that you have completed the Walkthrough: Creating a RIA Services Solution or have equivalent knowledge and an existing RIA Services solution available.
Creating a Complex Type with the Designer
Open the RIAServicesExample solution obtained from working through the Walkthrough: Creating a RIA Services Solution and open the AdventureWorksModel.edmx file (as it does by default) in the Entity Framework Designer.
Select the following properties from the Address entity: AddressLine1, AddressLine2, City, StateProvince, CountryRegion, and PostalCode.
Right-click on one of them and select Refactor into New Complex Type. This causes the Model Browser to open, where the complex type just created, named ComplexType1 by default, appears in the ComplexTypes folder of the AdventureWorksModel.edmx. The name specified in the Model Browser is actually the type of the new ComplexProperty. The subproperties that are encapsulated by this new complex property are now visible in the Model Browser.
Select ComplexType1 in the Model Browser and change it to MailAddress. This is now the type of the new ComplexProperty as can be verified by selecting the ComplexProperty in the Address entity and noting the type in the Properties window.
Change the Name of the new MailAddress type to MailAddress in the Properties window. Note that this new name now also appears in the Designer.
Select the MailAddress in the Designer, right-click and select Table Mapping to access the Mapping Details table. This table indicates how the properties are mapped into the table columns in the database.
The XML Representation of the Complex Type
RIA Services uses the conceptual schema definition language (CSDL) to specify data models. It is an XML-based language that describes the entities, relationships, and functions that make up a conceptual model of a data-driven application. The specification of the new MailAddress type is in the CSDL section of the XML.
To access this select AdventureWorksModel.edmx in the Solution Explorer, right-click and select Open With and then choose the XML (Text) Editor. Visual Studio 2010 will have to close the Design view of the data model to open the XML representation, so select Yes to approve this. Note that the new MailAddress property is specified within the element <EntityType Name=”Address”>:
<Property Name="MailAddress" Type="AdventureWorksLTModel.MailAddress" Nullable="false" />
The MailAddress property is defined in its own element below sections where the associations are defined.
<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>
Note that there is no <Key> element within a <ComplexType> element as there is in an <EntityType> element.
Reusing a Complex Type in another Entity
If we had a Manufacturer entity type that contained the same set of address properties, we could encapsulate them in the complex MailAddress type. Use the Refactor into New Complex Type as you did to create the complex type and then change the type and name in the Properties window. The fields will point back to their respective entities. For example, the City field for the MailAddress of the Address entity will map to Address.City, whereas this field will map to Manufacturer.City for the Manufacturer entity type. Use the Mapping Details table to make sure the properties map back to the correct columns in the database.