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