Presentation Models
[ This document was written for WCF Services Version 1 Service Pack 2 and might not be up to date Please see Release Notes or Changelog for a list of changes since WCF RIA Services ]
Open Ria Services enables you to create data models that aggregate data from multiple entities in the data access layer that are known as a presentation model. You use this feature when you do not want to directly expose the entities in your data access layer to the client. When using a presentation model, you can respond to changes in the data access layer by changing only the presentation model and not the client. Also, you can simplify the client code by designing a model that aggregates only those fields that are relevant to users of the client. This topic describes how to create, query and update a presentation model and how to pass values back to the client when changes have been set in either middle-tier or in the data source.

Creating the Presentation Model

The database structure that is needed to maintain data integrity may be more complicated than what you need for the entities in your client application. You can create a presentation model that simplifies this data structure by combining the fields that are relevant to your application into one presentation model. For example, in the AdventureWorksLT sample database, you retrieve customer and address data through the Customer, CustomerAddress, and Address tables.
RS_CustomerEntities
You create a presentation model by creating a class in the server project, and defining the properties you want to make available. The properties you define correspond to the properties you want to expose from the entities. For example, you can create the following CustomerPresentationModel class in the server project to present only the field you want from the Customer, CustomerAddress, and Address tables.
1
Public Class CustomerPresentationModel
2
<Key()> _
3
Public Property CustomerID As Integer
4
Public Property FirstName As String
5
Public Property LastName As String
6
Public Property EmailAddress As String
7
Public Property Phone As String
8
Public Property AddressType As String
9
Public Property AddressLine1 As String
10
Public Property AddressLine2 As String
11
Public Property City As String
12
Public Property StateProvince As String
13
Public Property PostalCode As String
14
Public Property AddressID As Integer
15
Public Property AddressModifiedDate As DateTime
16
Public Property CustomerModifiedDate As DateTime
17
End Class
Copied!
1
public class CustomerPresentationModel
2
{
3
[Key]
4
public int CustomerID { get; set; }
5
public string FirstName { get; set; }
6
public string LastName { get; set; }
7
public string EmailAddress { get; set; }
8
public string Phone { get; set; }
9
public string AddressType { get; set; }
10
public string AddressLine1 { get; set; }
11
public string AddressLine2 { get; set; }
12
public string City { get; set; }
13
public string StateProvince { get; set; }
14
public string PostalCode { get; set; }
15
public int AddressID { get; set; }
16
public DateTime AddressModifiedDate { get; set; }
17
public DateTime CustomerModifiedDate { get; set; }
18
}
Copied!

Querying and Modifying Values in the Presentation Model

After creating the presentation model, you expose it to the client project by adding a domain service that interacts with the presentation type. The entity values are only exposed through this domain service, and are not exposed through a domain service that exposes the whole entity. The following example shows a domain service that derives from the DomainService class.
1
[EnableClientAccess()]
2
public class CustomerDomainService : DomainService
3
{
4
AdventureWorksLT_DataEntities context = new AdventureWorksLT_DataEntities();
5
}
Copied!
To retrieve data, you add a query method to the domain service. In the query method, you retrieve the relevant data from the entities in the data access layer and set those values to the corresponding properties in a new instance of the presentation model. From the query method, you return either an instance of the presentation model type or an [T:System.Linq.IQueryable’1] where the generic type is your CustomerPresentationModel type. The following example shows a query method for the customer presentation model.
1
Public Function GetCustomersWithMainOffice() As IQueryable(Of CustomerPresentationModel)
2
Return From c In context.Customers
3
Join ca In context.CustomerAddresses On c.CustomerID Equals ca.CustomerID
4
Join a In context.Addresses On ca.AddressID Equals a.AddressID
5
Where ca.AddressType = "Main Office"
6
Select New CustomerPresentationModel() With _
7
{
8
.CustomerID = c.CustomerID,
9
.FirstName = c.FirstName,
10
.LastName = c.LastName,
11
.EmailAddress = c.EmailAddress,
12
.Phone = c.Phone,
13
.AddressType = ca.AddressType,
14
.AddressLine1 = a.AddressLine1,
15
.AddressLine2 = a.AddressLine2,
16
.City = a.City,
17
.StateProvince = a.StateProvince,
18
.PostalCode = a.PostalCode,
19
.AddressID = a.AddressID,
20
.AddressModifiedDate = a.ModifiedDate,
21
.CustomerModifiedDate = c.ModifiedDate
22
}
23
End Function
Copied!
1
public IQueryable<CustomerPresentationModel> GetCustomersWithMainOffice()
2
{
3
return from c in context.Customers
4
join ca in context.CustomerAddresses on c.CustomerID equals ca.CustomerID
5
join a in context.Addresses on ca.AddressID equals a.AddressID
6
where ca.AddressType == "Main Office"
7
select new CustomerPresentationModel()
8
{
9
CustomerID = c.CustomerID,
10
FirstName = c.FirstName,
11
LastName = c.LastName,
12
EmailAddress = c.EmailAddress,
13
Phone = c.Phone,
14
AddressType = ca.AddressType,
15
AddressLine1 = a.AddressLine1,
16
AddressLine2 = a.AddressLine2,
17
City = a.City,
18
StateProvince = a.StateProvince,
19
PostalCode = a.PostalCode,
20
AddressID = a.AddressID,
21
AddressModifiedDate = a.ModifiedDate,
22
CustomerModifiedDate = c.ModifiedDate
23
};
24
}
Copied!
Because the (Customer, CustomerAddress, and Address) entities in the data access layer are not exposed by the domain service, those types are not generated in the client project. Instead, only the CustomerPresentationModel type is generated in the client project.
To update data through the presentation model, you create an update method and define the logic for saving the values from the presentation model to the entities. An example of an update method is shown at the end of the next section.

Passing Values Back to the Client

After submitting changes, you may want to pass values back to the client that are set in either middle-tier logic or in the data source. Open Ria Services provides the [M:System.ServiceModel.DomainServices.Server.ChangeSet.Associate``2(``0,``1,System.Action`2)] method to map values from the entity back to the presentation model. In this method, you provide a callback method that is called after the changes have been submitted. In the callback method, you assign any values to the presentation model that have been modified in the middle tier. You perform this step to ensure that the client possesses the current values.
The following example shows how to update values in the entities and how to map modified data back to the presentation model.
1
<Update()> _
2
Public Sub UpdateCustomer(ByVal customerPM As CustomerPresentationModel)
3
Dim customerEntity As Customer = context.Customers.Where(Function(c) c.CustomerID = customerPM.CustomerID).FirstOrDefault()
4
Dim customerAddressEntity As CustomerAddress = context.CustomerAddresses.Where(Function(ca) ca.CustomerID = customerPM.CustomerID And ca.AddressID = customerPM.AddressID).FirstOrDefault()
5
Dim addressEntity As Address = context.Addresses.Where(Function(a) a.AddressID = customerPM.AddressID).FirstOrDefault()
6
​
7
customerEntity.FirstName = customerPM.FirstName
8
customerEntity.LastName = customerPM.LastName
9
customerEntity.EmailAddress = customerPM.EmailAddress
10
customerEntity.Phone = customerPM.Phone
11
customerAddressEntity.AddressType = customerPM.AddressType
12
addressEntity.AddressLine1 = customerPM.AddressLine1
13
addressEntity.AddressLine2 = customerPM.AddressLine2
14
addressEntity.City = customerPM.City
15
addressEntity.StateProvince = customerPM.StateProvince
16
addressEntity.PostalCode = customerPM.PostalCode
17
​
18
Dim originalValues As CustomerPresentationModel = Me.ChangeSet.GetOriginal(customerPM)
19
​
20
If (originalValues.FirstName <> customerPM.FirstName Or
21
originalValues.LastName <> customerPM.LastName Or
22
originalValues.EmailAddress <> customerPM.EmailAddress Or
23
originalValues.Phone <> customerPM.Phone) Then
24
customerEntity.ModifiedDate = DateTime.Now
25
End If
26
​
27
If (originalValues.AddressLine1 <> customerPM.AddressLine1 Or
28
originalValues.AddressLine2 <> customerPM.AddressLine2 Or
29
originalValues.City <> customerPM.City Or
30
originalValues.StateProvince <> customerPM.StateProvince Or
31
originalValues.PostalCode <> customerPM.PostalCode) Then
32
addressEntity.ModifiedDate = DateTime.Now
33
End If
34
​
35
context.SaveChanges()
36
​
37
Me.ChangeSet.Associate(customerPM, customerEntity, AddressOf MapCustomerToCustomerPM)
38
Me.ChangeSet.Associate(customerPM, addressEntity, AddressOf MapAddressToCustomerPM)
39
End Sub
40
​
41
Private Sub MapCustomerToCustomerPM(ByVal customerPM As CustomerPresentationModel, ByVal customerEntity As Customer)
42
customerPM.CustomerModifiedDate = customerEntity.ModifiedDate
43
End Sub
44
​
45
Private Sub MapAddressToCustomerPM(ByVal customerPM As CustomerPresentationModel, ByVal addressEntity As Address)
46
customerPM.AddressModifiedDate = addressEntity.ModifiedDate
47
End Sub
Copied!
1
[Update]
2
public void UpdateCustomer(CustomerPresentationModel customerPM)
3
{
4
Customer customerEntity = context.Customers.Where(c => c.CustomerID == customerPM.CustomerID).FirstOrDefault();
5
CustomerAddress customerAddressEntity = context.CustomerAddresses.Where(ca => ca.CustomerID == customerPM.CustomerID && ca.AddressID == customerPM.AddressID).FirstOrDefault();
6
Address addressEntity = context.Addresses.Where(a => a.AddressID == customerPM.AddressID).FirstOrDefault();
7
​
8
customerEntity.FirstName = customerPM.FirstName;
9
customerEntity.LastName = customerPM.LastName;
10
customerEntity.EmailAddress = customerPM.EmailAddress;
11
customerEntity.Phone = customerPM.Phone;
12
customerAddressEntity.AddressType = customerPM.AddressType;
13
addressEntity.AddressLine1 = customerPM.AddressLine1;
14
addressEntity.AddressLine2 = customerPM.AddressLine2;
15
addressEntity.City = customerPM.City;
16
addressEntity.StateProvince = customerPM.StateProvince;
17
addressEntity.PostalCode = customerPM.PostalCode;
18
​
19
CustomerPresentationModel originalValues = this.ChangeSet.GetOriginal(customerPM);
20
​
21
if (originalValues.FirstName != customerPM.FirstName ||
22
originalValues.LastName != customerPM.LastName ||
23
originalValues.EmailAddress != customerPM.EmailAddress ||
24
originalValues.Phone != customerPM.Phone)
25
{
26
customerEntity.ModifiedDate = DateTime.Now;
27
}
28
​
29
if (originalValues.AddressLine1 != customerPM.AddressLine1 ||
30
originalValues.AddressLine2 != customerPM.AddressLine2 ||
31
originalValues.City != customerPM.City ||
32
originalValues.StateProvince != customerPM.StateProvince ||
33
originalValues.PostalCode != customerPM.PostalCode)
34
{
35
addressEntity.ModifiedDate = DateTime.Now;
36
}
37
​
38
context.SaveChanges();
39
​
40
this.ChangeSet.Associate(customerPM, customerEntity, MapCustomerToCustomerPM);
41
this.ChangeSet.Associate(customerPM, addressEntity, MapAddressToCustomerPM);
42
}
43
​
44
private void MapCustomerToCustomerPM(CustomerPresentationModel customerPM, Customer customerEntity)
45
{
46
customerPM.CustomerModifiedDate = customerEntity.ModifiedDate;
47
}
48
​
49
private void MapAddressToCustomerPM(CustomerPresentationModel customerPM, Address addressEntity)
50
{
51
customerPM.AddressModifiedDate = addressEntity.ModifiedDate;
52
}
Copied!
Last modified 6mo ago