This sample application demonstrates use of the new

advertisement
RIA Services ComplexTypes Sample
Contents
Overview ....................................................................................................................................................... 1
Application Details ........................................................................................................................................ 1
Running the sample .................................................................................................................................. 3
ComplexTypes in the EntityFramework Data Model ................................................................................ 3
ComplexType usage in RIA Services .......................................................................................................... 5
Standard Create/Update/Delete Functionality......................................................................................... 6
ComplexType Parameters in DomainService Operations ......................................................................... 7
ComplexType UI Binding ........................................................................................................................... 8
Cross-Tier Validation ............................................................................................................................... 10
IEditableObject Behavior ........................................................................................................................ 11
SubmitChanges/RejectChanges .............................................................................................................. 12
Overview
This sample application demonstrates use of the new ComplexTypes feature in a variety of scenarios,
including:



Use of EntityFramework mapped complex types in the data model, both as nested Entity
members as well as mapped stored procedure return types
Use of POCO complex types as parameters to DomainService invoke operations
Use of complex types as return values from DomainService invoke operations
Application Details
The sample app was created using the Silverlight Business Application Template. The Order
Management page allows you to select a customer, at which time the orders for that customer are
asynchronously loaded in a master/details view:
The Customer Management page shows a master/detail view of Customers, and also displays the order
history for the selected customer. These results are loaded on demand as customers are selected by
executing an Invoke operation mapped to a sproc:
Running the sample
To run the sample, open and run the ComplexTypesSample solution. The application attaches two
databases to the local SqlExpress instance (a Northwind database and the ASP.NET database used for
authentication). Notes on the app:



The sample requires the following to be installed:
o WCF RIA Services V1SP1
o The Silverlight 4 Toolkit
o SqlExpress
When the initial app screen is displayed you must log in. The default database is configured with
the sample credentials UserName=daboss, Password=imtheboss! Both the login screen as well
as the “register new user” screen use ComplexTypes in their implementation (details below). To
facilitate playing with the app, select the “Keep me signed in” option on the login page:
Once logged in you can navigate to the Order Management and Customer Management pages.
Each of these pages bind to ComplexTypes in different ways (details below).
The pages support edit and submit/reject demonstrating use of ComplexTypes in DataForm and
DataGrid binding scenarios, as well as in update scenarios.
ComplexTypes in the EntityFramework Data Model
Opening the Northwind.edmx file in the server project Models folder you can see how several EF
complex types have been mapped in the model. The EF model browser shows the two types:
The Address CT is shared by both the Customer Entity as well as the Order entity, where the address
details for each are mapped to the CT. Creation of a new complex type can be done in the EF designer
simply by selecting one or more properties of an entity and selecting “Refactor into new Complex Type”
context menu option. After this is done the set of properties will now be exposed by the entity as a
single CT property:
You can then use the Mapping Details window to map the database columns to your CT properties:
In a similar way, you can also map a sproc return Type to a CT. In this sample I mapped the
CustOrdHistory sproc to a new CT Type CustomerOrderHistoryResult:
This sproc is used in the sample app exposed by the CustomerManagement service
GetCustomerOrderHistory operation.
ComplexType usage in RIA Services
The generated Northwind ObjectContext for the above model is used in this sample by both the
CustomerManagement and OrderManagement DomainServices. RIA Services recognizes these types as
ComplexTypes and uses this information during codegen to generate the corresponding proxy Types,
members and methods. For example, in the client project an Address class has been generated that
derives from ComplexObject:
The Order and Customer entities have corresponding ComplexObject properties generated. You’ll also
notice that the metadata pipeline for CTs behaves the same way it does for entities. For example, you
can apply additional metadata via a “buddy class”. In addition, some of the EF model metadata also
flows to the client. Below you can see both a Max Length model attribute as well as a buddy class
DisplayAttribute being carried to the client codegen:
Standard Create/Update/Delete Functionality
The Order.ShipAddress and Customer.Address CT properties participate in updates as you’d expect. The
client detects modifications, performs cross tier validation, etc. On the server, an updated entity with CT
member updates is attached normally.
ComplexType Parameters in DomainService Operations
ComplexTypes can be passed as parameters to Invoke and Custom Update operations, and can be
returned from Invoke operations. In the sample, the CustomerOrderHistory sproc is exposed in the
CustomerManagement service via an Invoke operation and it returns a collection of CTs:
This DomainService method results in a CustomerOrerHistoryResult ComplexObject being generated on
the client, along with a corresponding Invoke operation on the CustomerManagement DomainContext:
As an example of POCO CTs that aren’t mapped in the EntityFramework model, this sample has two
examples. First the UserRegistrationService RegistrationData class has been updated to be a CT:
On the client this is codegenned as a CT deriving from ComplexObject. The full IEditableObject and
Validation behavior provided by the ComplexObject base class can be seen in the UI:
Similarly the LoginInfo Type used on the login screen has also been made a ComplexObject. These
modifications to the standard Business Application Template (BAT) to use ComplexTypes will be made in
the actual product soon. This will allow us to remove several workarounds the BAT currently employs.
ComplexType UI Binding
In general the binding story for CT properties is straight forward – in your xaml you simply use dotted
paths to reference the nested CT properties. Since ComplexObject implements the right set of binding
interfaces (INotifyPropertyChanged, IEditableObject, INotifyDataErrorInfo), you get rich UI functionality.
Below the DataForm xaml and resulting UI are shown for the bound members of Order.ShipAddress:
Since DataForm wasn’t designed to do deep change tracking on nested instances, it doesn’t work
properly in update scenarios where you’re modifying nested CT properties. The underlying issue is that
the DataForm only tracks top level properties to determine if the current instance has been modified in
the session. This will result in the commit/cancel buttons not behaving properly. This sample works
around this by configuring the DataForm in a certain way (AutoEdit="False" AutoCommit="True"
CommandButtonsVisibility="Edit, Cancel"). You can also create your own update UI bound to your
CTs and control the entire experience yourself.
The sample also demonstrates the validation behavior of ComplexObject in nesting scenarios. In the
below scenario, the Order.ShipAddress.PostalCode member has been set to an invalid value. You see the
error reported on the control itself since Address instance implements INDEI which the control is bound
to. In addition, the error summary control is bound to INDEI on the Order instance – this demonstrates
that nested CT instances report their validation attributes up to their parent.
Cross-Tier Validation
Above you saw client side validation occurring as properties were set. As with entities, all this validation
also runs server side. In addition to validation that runs on both tiers, you can also have server side only
validation (declarative or imperative). In the sample, the UpdateCustomer method the
Customer.Address.Country member is validated:
Notice that on the server the dotted path to the invalid member is specified. This validation error will be
sent back to the client, and the error will be applied down the hierarchy, ultimately registering on the
Customer.Address.Country member which will cause the UI to display the server error:
IEditableObject Behavior
Since ComplexObject implements IEO, when bound to a DataForm or other control providing edit
sessions based on this interface, changes can be committed/cancelled easily. Below, the current Order
has been put into edit mode and a property has been changed. Hitting the Cancel button will cancel the
edit and the value will be reverted. To commit the edit, navigate to another Order (again working
around the issue that the DataForm Commit button doesn’t work for nested CT edits).
SubmitChanges/RejectChanges
Once one or more edits have been made, the Save/Reject buttons will become enabled. You can set a
breakpoint on the server to see that the nested CT instance is sent as part of the changeset and will be
populated in both the current and original instances passed to your update method.
As with entities, the RoundtripOriginalAttribute governs which properties are roundtripped to the
server as part of the original object. You must either mark the members of your ComplexType as
ConcurrencyMode=Fixed in your EF model (in which case the FX will infer RTO for you), or via the buddy
class:
In addition to setting the concurrency mode on the individual members of the ComplexType, you must
also apply RoundtripOriginalAttribute on the Order.ShipAddress property itself. See the Order and
Customer buddy metadata classes in the sample.
Download