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