Presentation Models

WCF RIA Services

[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.]

WCF 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.

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.


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.

public class CustomerPresentationModel
    public int CustomerID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string EmailAddress { get; set; }
    public string Phone { get; set; }
    public string AddressType { get; set; }
    public string AddressLine1 { get; set; }
    public string AddressLine2 { get; set; }
    public string City { get; set; }
    public string StateProvince { get; set; }
    public string PostalCode { get; set; }
    public int AddressID { get; set; }
    public DateTime AddressModifiedDate { get; set; }
    public DateTime CustomerModifiedDate { get; set; }

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.

public class CustomerDomainService : DomainService
    AdventureWorksLT_DataEntities context = new AdventureWorksLT_DataEntities();

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.

public IQueryable<CustomerPresentationModel> GetCustomersWithMainOffice()
    return from c in context.Customers
        join ca in context.CustomerAddresses on c.CustomerID equals ca.CustomerID
        join a in context.Addresses on ca.AddressID equals a.AddressID
        where ca.AddressType == "Main Office"
           select new CustomerPresentationModel()
               CustomerID = c.CustomerID,
               FirstName = c.FirstName,
               LastName = c.LastName,
               EmailAddress = c.EmailAddress,
               Phone = c.Phone,
               AddressType = ca.AddressType, 
               AddressLine1 = a.AddressLine1, 
               AddressLine2 = a.AddressLine2,
               City = a.City, 
               StateProvince = a.StateProvince, 
               PostalCode = a.PostalCode,
               AddressID = a.AddressID,
               AddressModifiedDate = a.ModifiedDate,
               CustomerModifiedDate = c.ModifiedDate

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.

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. 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.

public void UpdateCustomer(CustomerPresentationModel customerPM)
    Customer customerEntity = context.Customers.Where(c => c.CustomerID == customerPM.CustomerID).FirstOrDefault();
    CustomerAddress customerAddressEntity = context.CustomerAddresses.Where(ca => ca.CustomerID == customerPM.CustomerID && ca.AddressID == customerPM.AddressID).FirstOrDefault();
    Address addressEntity = context.Addresses.Where(a => a.AddressID == customerPM.AddressID).FirstOrDefault();

    customerEntity.FirstName = customerPM.FirstName;
    customerEntity.LastName = customerPM.LastName;
    customerEntity.EmailAddress = customerPM.EmailAddress;
    customerEntity.Phone = customerPM.Phone;
    customerAddressEntity.AddressType = customerPM.AddressType;
    addressEntity.AddressLine1 = customerPM.AddressLine1;
    addressEntity.AddressLine2 = customerPM.AddressLine2;
    addressEntity.City = customerPM.City;
    addressEntity.StateProvince = customerPM.StateProvince;
    addressEntity.PostalCode = customerPM.PostalCode;

    CustomerPresentationModel originalValues = this.ChangeSet.GetOriginal(customerPM);

    if (originalValues.FirstName != customerPM.FirstName ||
        originalValues.LastName != customerPM.LastName ||
        originalValues.EmailAddress != customerPM.EmailAddress ||
        originalValues.Phone != customerPM.Phone)
        customerEntity.ModifiedDate = DateTime.Now;

    if (originalValues.AddressLine1 != customerPM.AddressLine1 ||
        originalValues.AddressLine2 != customerPM.AddressLine2 ||
        originalValues.City != customerPM.City ||
        originalValues.StateProvince != customerPM.StateProvince ||
        originalValues.PostalCode != customerPM.PostalCode)
        addressEntity.ModifiedDate = DateTime.Now;


    this.ChangeSet.Associate(customerPM, customerEntity, MapCustomerToCustomerPM);
    this.ChangeSet.Associate(customerPM, addressEntity, MapAddressToCustomerPM);

private void MapCustomerToCustomerPM(CustomerPresentationModel customerPM, Customer customerEntity)
    customerPM.CustomerModifiedDate = customerEntity.ModifiedDate;

private void MapAddressToCustomerPM(CustomerPresentationModel customerPM, Address addressEntity)
    customerPM.AddressModifiedDate = addressEntity.ModifiedDate;