表示模型

WCF RIA Services 允许您创建从数据访问层的多个实体聚合数据的数据模型,即表示模型。当您不想直接将数据访问层中的实体公开给客户端时,可以使用此功能。使用表示模型时,可以通过只更改表示模型而不更改客户端来响应数据访问层中的更改。此外,通过设计只聚合与客户端的用户有关的那些字段的模型,可以简化客户端代码。本主题说明如何创建、查询和更新一个表示模型以及在中间层或数据源中设置更改时如何将值传回客户端。

创建表示模型

维护数据完整性所需的数据库结构可能比客户端应用程序中的实体所需的数据库结构复杂。您可以通过将与您的应用程序有关的字段合并到一个表示模型,创建简化此数据结构的表示模型。例如,在 AdventureWorksLT 示例数据库中,您通过 CustomerCustomerAddressAddress 表检索客户和地址数据。

RS_CustomerEntities

通过在服务器项目中创建一个类并定义可用的属性,创建一个表示模型。您定义的属性对应于要从实体公开的属性。例如,您可以在服务器项目中创建以下 CustomerPresentationModel 类以只表示来自 CustomerCustomerAddressAddress 表的所需字段。

Public Class CustomerPresentationModel
    <Key()> _
    Public Property CustomerID As Integer
    Public Property FirstName As String
    Public Property LastName As String
    Public Property EmailAddress As String
    Public Property Phone As String
    Public Property AddressType As String
    Public Property AddressLine1 As String
    Public Property AddressLine2 As String
    Public Property City As String
    Public Property StateProvince As String
    Public Property PostalCode As String
    Public Property AddressID As Integer
    Public Property AddressModifiedDate As DateTime
    Public Property CustomerModifiedDate As DateTime
End Class
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 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; }
}

查询和修改表示模型中的值

创建表示模型后,通过添加与表示类型交互的域服务,将该模型公开给客户端项目。只通过此域服务公开实体值,而不通过公开整个实体的域服务来公开。下面的示例显示从 DomainService 类派生的域服务。

[EnableClientAccess()]
public class CustomerDomainService : DomainService
{
    AdventureWorksLT_DataEntities context = new AdventureWorksLT_DataEntities();
}

为了检索数据,您将一个查询方法添加到该域服务。在该查询方法中,您从数据访问层中的实体检索相关数据并将这些值设置为该表示模型的新实例中的相应属性。从该查询方法,您返回该表示模型类型的一个实例或一个 IQueryable’1(其中通用类型为您的 CustomerPresentationModel 类型)。下面的示例显示针对客户表示模型的一个查询方法。

Public Function GetCustomersWithMainOffice() As IQueryable(Of CustomerPresentationModel)
    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() With _
               {
                   .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
               }
End Function
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
           };
}

由于数据访问层中的(CustomerCustomerAddressAddress)实体不通过域服务公开,因此不在客户端项目中生成那些类型。只在客户端项目中生成 CustomerPresentationModel 类型。

为了通过该表示模型更新数据,您创建了一个更新方法并定义用于将该表示模型中的值保存到实体的逻辑。下一节的末尾显示一个更新方法的示例。

将值传回到客户端

在提交更改后,您可能要将值传回到在中间层逻辑或数据源中设置的客户端。RIA Services 提供 Associate 方法来将实体的值映射回该表示模型。在此方法中,您提供一个在提交更改后调用的回调方法。在该回调方法中,您将任意值分配给已在中间层中修改的表示模型。您执行此步骤以确保客户端具有当前值。

下面的示例显示如何更新实体中的值以及如何将已修改的数据映射回表示模型:

<Update()> _
Public Sub UpdateCustomer(ByVal customerPM As CustomerPresentationModel)
    Dim customerEntity As Customer = context.Customers.Where(Function(c) c.CustomerID = customerPM.CustomerID).FirstOrDefault()
    Dim customerAddressEntity As CustomerAddress = context.CustomerAddresses.Where(Function(ca) ca.CustomerID = customerPM.CustomerID And ca.AddressID = customerPM.AddressID).FirstOrDefault()
    Dim addressEntity As Address = context.Addresses.Where(Function(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

    Dim originalValues As CustomerPresentationModel = Me.ChangeSet.GetOriginal(customerPM)

    If (originalValues.FirstName <> customerPM.FirstName Or
            originalValues.LastName <> customerPM.LastName Or
            originalValues.EmailAddress <> customerPM.EmailAddress Or
            originalValues.Phone <> customerPM.Phone) Then
        customerEntity.ModifiedDate = DateTime.Now
    End If

    If (originalValues.AddressLine1 <> customerPM.AddressLine1 Or
            originalValues.AddressLine2 <> customerPM.AddressLine2 Or
            originalValues.City <> customerPM.City Or
            originalValues.StateProvince <> customerPM.StateProvince Or
            originalValues.PostalCode <> customerPM.PostalCode) Then
        addressEntity.ModifiedDate = DateTime.Now
    End If

    context.SaveChanges()

    Me.ChangeSet.Associate(customerPM, customerEntity, AddressOf MapCustomerToCustomerPM)
    Me.ChangeSet.Associate(customerPM, addressEntity, AddressOf MapAddressToCustomerPM)
End Sub

Private Sub MapCustomerToCustomerPM(ByVal customerPM As CustomerPresentationModel, ByVal customerEntity As Customer)
    customerPM.CustomerModifiedDate = customerEntity.ModifiedDate
End Sub

Private Sub MapAddressToCustomerPM(ByVal customerPM As CustomerPresentationModel, ByVal addressEntity As Address)
    customerPM.AddressModifiedDate = addressEntity.ModifiedDate
End Sub
[Update]
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;
    }

    context.SaveChanges();

    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;
}