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.
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:
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
.
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.
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 Customer
, CustomerAddress
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.
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;
cont=new ADVWORKDomainContext();
System.ServiceModel.DomainServices.Client.LoadOperation<CustomerPresentationModel>
lp= cont.Load(cont.GetCustomersWithAddressQuery());
lp.Completed+=new EventHandler(lp_Completed);
System.Windows.Data.PagedCollectionView pagedcollview =
new System.Windows.Data.PagedCollectionView(lp.Entities);
dpCustomers.Source = pagedcollview;
dgCustomers.ItemsSource = pagedcollview;
}
On executing the project, we will find the result as follows:
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.