Condividi tramite


Modelli di presentazione

WCF RIA Services consente di creare modelli di dati che aggregano i dati da più entità nel livello di accesso ai dati, noti come modelli di presentazione. Si utilizza questa caratteristica quando non si desidera esporre le entità nel livello di accesso ai dati direttamente al client. Quando si utilizza un modello di presentazione, è possibile rispondere alle modifiche nel livello di accesso ai dati modificando solo il modello di presentazione e non il client. Inoltre, è possibile semplificare il codice client progettando un modello che aggrega solo i campi rilevanti per gli utenti del client. In questo argomento viene descritto come creare, sottoporre a query e aggiornare un modello di presentazione nonché come passare nuovamente i valori al client quando le modifiche sono state impostate nel livello intermedio o nell'origine dati.

Creazione del modello di presentazione

La struttura del database necessaria a gestire l'integrità dei dati potrebbe essere più complicata di quanto è richiesto per le entità nell'applicazione client. È possibile creare un modello di presentazione che semplifichi questa struttura di dati combinando i campi rilevanti per l'applicazione in un modello di presentazione. Ad esempio, nel database di esempio AdventureWorksLT, si recuperano i dati dell'indirizzo e del cliente tramite le tabelle Customer, CustomerAddress e Address.

RS_CustomerEntities

Si crea un modello di presentazione tramite la creazione di una classe nel progetto server e la definizione delle proprietà che si desidera siano disponibili. Le proprietà che si definiscono corrispondono alle proprietà che si desidera vengano esposte dalle entità. Ad esempio, è possibile creare la seguente classe CustomerPresentationModel nel progetto server per presentare solo il campo desiderato dalle tabelle Customer, CustomerAddress e 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; }
}

Esecuzione di query e modifica di valori nel modello di presentazione

Dopo aver creato il modello di presentazione, lo si espone al progetto client aggiungendo un servizio del dominio che interagisce con il tipo di presentazione. I valori dell'entità sono esposti solo tramite questo servizio del dominio e tramite un servizio del dominio che espone l'entità intera. Nell'esempio seguente viene illustrato un servizio del dominio che deriva dalla classe DomainService.

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

Per recuperare i dati, si aggiunge un metodo di query al servizio del dominio. Nel metodo di query si recuperano i dati pertinenti dalle entità nel livello di accesso ai dati e si impostano quei valori sulle proprietà corrispondenti in una nuova istanza del modello di presentazione. Dal metodo di query viene restituita un'istanza del tipo di modello di presentazione o un elemento IQueryable’1 dove il tipo generico è il tipo CustomerPresentationModel del cliente. Nell'esempio seguente viene mostrato un metodo di query per il modello di presentazione del 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
           };
}

Poiché le entità (Customer, CustomerAddress e Address) nel livello di accesso ai dati non sono esposte tramite il servizio del dominio, tali tipi non vengono generati nel progetto client. Nel progetto client viene invece generato solo il tipo CustomerPresentationModel.

Per aggiornare i dati tramite il modello di presentazione, creare un metodo di aggiornamento e definire la logica per salvare i valori dal modello di presentazione nelle entità. Un esempio di metodo di aggiornamento è riportato alla fine della prossima sezione.

Passaggio dei valori di nuovo nel client

Una volta inviate le modifiche, è possibile che si debbano passare nuovamente al client i valori impostati nella logica del livello intermedio o nell'origine dati. RIA Services fornisce il metodo Associate per eseguire nuovamente il mapping dei valori dall'entità al modello di presentazione. In questo metodo, si fornisce un metodo di callback chiamato dopo che sono state inviate le modifiche. Nel metodo di callback, si assegna al modello di presentazione qualsiasi valore che è stato modificato nel livello intermedio. Si esegue questo passaggio per assicurarsi che il client disponga dei valori correnti.

Nell'esempio seguente viene mostrato come aggiornare i valori nelle entità e come eseguire nuovamente il mapping dei dati modificati nel modello di presentazione.

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