Modelos de presentación

WCF RIA Services permite crear modelos de datos que agregan datos de varias entidades en la capa de acceso a datos; se conocen como modelo de presentación. Esta característica se utiliza cuando no se desea exponer directamente las entidades al cliente en la capa de acceso a datos. Cuando se utiliza un modelo de presentación, puede responder a los cambios en la capa de acceso a datos cambiando solo el modelo de presentación y no el cliente. Asimismo, puede simplificar el código de cliente diseñando un modelo que agregue solo los campos que son relevantes para los usuarios del cliente. En este tema se describe cómo crear, consultar y actualizar un modelo de presentación y cómo devolver valores al cliente cuando se han establecido cambios en el nivel intermedio o en el origen de datos.

Crear el modelo de presentación

La estructura de base de datos que se necesita para mantener la integridad de los datos puede ser más complicada que la que se necesita para las entidades en la aplicación cliente. Puede crear un modelo de presentación que simplifique esta estructura de datos combinando los campos que son relevantes para la aplicación en un modelo de presentación. Por ejemplo, en la base de datos de ejemplo AdventureWorksLT, puede recuperar datos de cliente y de dirección mediante las tablas Customer, CustomerAddress y Address.

RS_CustomerEntities

Un modelo de presentación se genera creando una clase en el proyecto de servidor y definiendo las propiedades que se desea que estén disponibles. Las propiedades que defina corresponderán a las propiedades que desee exponer de las entidades. Por ejemplo, puede crear la siguiente clase CustomerPresentationModel en el proyecto de servidor para presentar solamente el campo que desee de las tablas Customer, CustomerAddress y Address.

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

Consultar y modificar valores en el modelo de presentación

Después de crear el modelo de presentación, puede exponerlo al proyecto de cliente agregando un servicio de dominio que interactúe con el tipo de presentación. Los valores de entidad solo se exponen a través de este servicio de dominio y no se exponen a través de un servicio de dominio que exponga la entidad completa. En el ejemplo siguiente se muestra un servicio de dominio que deriva de la clase DomainService.

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

Para recuperar datos, debe agregar un método de consulta al servicio de dominio. En el método de consulta, recuperará los datos relevantes de las entidades en la capa de acceso a datos y establecerá esos valores en las propiedades correspondientes de una nueva instancia del modelo de presentación. Desde el método de consulta, devolverá una instancia del tipo de modelo de presentación o un elemento IQueryable’1 donde el tipo genérico es el tipo CustomerPresentationModel. En el siguiente ejemplo se muestra un método de consulta para el modelo de presentación de cliente.

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

Dado que las entidades (Customer, CustomerAddress y Address) de la capa de acceso a datos no las expone el servicio de dominio, esos tipos no se generan en el proyecto de cliente. En su lugar, solo el tipo CustomerPresentationModel se genera en el proyecto de cliente.

Para actualizar los datos mediante el modelo de presentación, debe crear un método de actualización y definir la lógica para guardar los valores del modelo de presentación en las entidades. Al final de la sección siguiente se muestra un ejemplo de un método de actualización.

Devolver valores al cliente

Después de enviar los cambios, es posible que desee devolver al cliente los valores que se establecen en la lógica de nivel intermedio o en el origen de datos. RIA Services proporciona el método Associate para asignar valores de la entidad al modelo de presentación. En este método, proporcionará un método de devolución de llamada que se invoca después de haberse enviado los cambios. En el método de devolución de llamada, asignará al modelo de presentación los valores que se hayan modificado en el nivel intermedio. Realizará este paso para asegurarse de que el cliente posee los valores actuales.

En el siguiente ejemplo se muestra cómo actualizar valores en las entidades y cómo asignar datos modificados al modelo de presentación.

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