Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Data Aggregation Using Presentation Model in RIA and Silverlight 4

0.00/5 (No votes)
13 Apr 2011 1  
An in-depth look into the Presentation Model and its mode of handling related multiple entities

Introduction

My earlier post was about the basic CRUD operations on entities with relations. We discussed about creating a simple association and querying, as well as invoking CRUD operations on them. Here in this article, we will have an in-depth look into the Presentation Model and its mode of handling related multiple entities.

Introduction: What is Presentation Model?

The Presentation Model deals with data from more than one entity which are related to each other and project it as one entity.

We usually come across situations where there is no need to expose all the entities to the client side, either for security reasons or to avoid unnecessary code at the client side. So instead of exposing everything as separate entities, we can aggregate the data as a separate dummy to the client or to the presentation layer and can invoke operations on it.

Presentation Model in RIA and Silverlight 4

Case Study

Let's check a Data Model from the AdventureWorksLT database for online transactions. AdventureWorksLT is a sample SQL Server database from Microsoft. You can find the database schema in the following image:

AdventureWorksLTDetail

More details regarding the database can be found here. Also, you can download database samples from CodePlex with the following links: AdventureWorksLT 2005 version, AdventureWorksLT 2008 version. For the Presentation Model scenario, I am going to use a part of the Data Model which involves Customer and Address.

Presentation Model in RIA and Silverlight 4

Normally we expose Customer, CustomerAddress, and Address to the client side as three separate entities and apply an association between them and show the results by joining them using LINQ at the client side. Instead of the above procedure, we will look into how to create a dummy entity and send only the required combined property to the client side.

Setting Up the Project

The first step involves creating a class for the entity in the server side project which will hold the custom properties we want to propagate. Let's name it CustomerPresentationModel.cs.

public class CustomerPresentationModel 
{ 
    [Key] 
    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 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; } 
}

Well, the basic step needs no elaboration. You can refer to my previous post for setting up a project using the Entity Framework and RIA. Download the AdventureLT database and create a project as mentioned in my earlier articles. Add a domain service named ADVWORKDomainService without selecting the entity from the wizard.

image

Querying Data from Data Model

The first step involved is adding a method that will return all the Customers with properties we want to expose. So create a method with in the domainservice at server side project that will fetch the data from the CustomerCustomerAddress and Address entities and project it as CustomerPresentationModel.

public IQueryable<CustomerPresentationModel> GetCustomersWithAddress() 
{ 
    return from c in this.ObjectContext.Customers 
    join ca in this.ObjectContext.CustomerAddresses on c.CustomerID equals ca.CustomerID 
    join a in this.ObjectContext.Addresses on ca.AddressID equals a.AddressID 
    select new CustomerPresentationModel() 
    { 
        CustomerID = c.CustomerID, 
        FirstName = c.FirstName, 
        LastName = c.LastName, 
        EmailAddress = c.EmailAddress, 
        Phone = c.Phone, 
        AddressLine1 = a.AddressLine1, 
        AddressLine2 = a.AddressLine2, 
        City = a.City, 
        StateProvince = a.StateProvince, 
        PostalCode = a.PostalCode, 
        AddressID = a.AddressID, 
        AddressModifiedDate = a.ModifiedDate, 
        CustomerModifiedDate = c.ModifiedDate 
    }; 
}

Build the project and we will find the CustomerPresentationModel alone is propagated to the client side instead of all the three separate entities.

image

Presentation Model in RIA and Silverlight 4

Execute this method asynchronously from the Silverlight project and bind the result to the data grid.

private void LayoutRoot_Loaded(object sender, RoutedEventArgs e) 
{ 
    biLoading.IsBusy = true; 
    //Module level DomainContext 
    cont=new ADVWORKDomainContext(); 
    //Call the Domain Service Method to fill
    //the CustomerPresentationModel from 3 entities 
    System.ServiceModel.DomainServices.Client.LoadOperation<CustomerPresentationModel> 
           lp= cont.Load(cont.GetCustomersWithAddressQuery()); 
    //Attach OnCompleted Event handaler 
    lp.Completed+=new EventHandler(lp_Completed); 
    //Create Pagination for Grid 
    System.Windows.Data.PagedCollectionView pagedcollview = 
       new System.Windows.Data.PagedCollectionView(lp.Entities); 
    dpCustomers.Source = pagedcollview; 
    //Assign Paged Collection to the Grid 
    dgCustomers.ItemsSource = pagedcollview; 
}

On executing the project, we will find the result as follows:

Presentation Model in RIA and Silverlight 4

Updating the Presentation Model

We are now able to fetch the data from the Data layer using the Presentation Model. Obviously, the next step involves updating the entities from the presented model from the Silverlight page. So we need to add another method to the domain service class on the server side to save the changes back to the model and the database. Let's add a method with the Update attribute wrapper:

[Update] 
public void UpdateCustomer(CustomerPresentationModel customerPM) 
{ 
    Customer customerEntity = this.ObjectContext.Customers.Where(
      c => c.CustomerID == customerPM.CustomerID).FirstOrDefault(); 
    CustomerAddress customerAddressEntity = 
      this.ObjectContext.CustomerAddresses.Where(
      ca => ca.CustomerID == customerPM.CustomerID && 
      ca.AddressID == customerPM.AddressID).FirstOrDefault(); 
    Address addressEntity = this.ObjectContext.Addresses.Where(
      a => a.AddressID == customerPM.AddressID).FirstOrDefault(); 
    customerEntity.FirstName = customerPM.FirstName; 
    customerEntity.LastName = customerPM.LastName; 
    customerEntity.EmailAddress = customerPM.EmailAddress; 
    customerEntity.Phone = customerPM.Phone; 
    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.ObjectContext.SaveChanges(); 
}

The following piece of code of the above method creates three entities based on their IDs:

Customer customerEntity = 
  this.ObjectContext.Customers.Where(
  c => c.CustomerID == customerPM.CustomerID).FirstOrDefault(); 
CustomerAddress customerAddressEntity = 
  this.ObjectContext.CustomerAddresses.Where(
  ca => ca.CustomerID == customerPM.CustomerID && 
  ca.AddressID == customerPM.AddressID).FirstOrDefault(); 
Address addressEntity = this.ObjectContext.Addresses.Where(
  a => a.AddressID == customerPM.AddressID).FirstOrDefault();

and then the next steps follow with assigning the changed values, followed by saving the changes.

Conclusion

The Presentation Model can use Custom Entities built for the presentation layer instead of directly using the data model structure. As I say, the implementation is completely dependent on the scenario and security. Hope this article is detailed enough to explain how to start with the presentation model. Keep suggesting.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here