次の方法で共有


プレゼンテーション モデル

WCF RIA サービス を使用すると、プレゼンテーション モデルと呼ばれるデータ アクセス層内の複数のエンティティからデータを集計するデータ モデルを作成できます。この機能は、データ アクセス層内のエンティティをクライアントに直接公開しないようにする場合に使用します。プレゼンテーション モデルを使用すると、クライアントではなくプレゼンテーション モデルのみを変更することで、データ アクセス層での変更に対応できます。また、クライアントのユーザーに関連するフィールドだけを集計するモデルをデザインすることで、クライアント コードを簡略化できます。ここでは、プレゼンテーション モデルを作成、照会、および更新する方法と、中間層またはデータ ソースで変更が設定されている場合にクライアントに値を渡す方法について説明します。

プレゼンテーション モデルの作成

データの整合性を維持するために必要なデータベース構造は、クライアント アプリケーションのエンティティに必要な構造よりも複雑なことがあります。アプリケーションに関連する複数のフィールドを結合して 1 つのプレゼンテーション モデルにすることで、このデータ構造を簡略化するプレゼンテーション モデルを作成できます。たとえば、AdventureWorksLT サンプル データベースでは、CustomerCustomerAddress、および Address の各テーブルを使用して顧客データと住所データを取得します。

RS_CustomerEntities

プレゼンテーション モデルを作成するには、サーバー プロジェクトにクラスを作成し、使用できるようにするプロパティを定義します。定義するプロパティは、エンティティから公開するプロパティに対応します。たとえば、サーバー プロジェクト内に次の CustomerPresentationModel クラスを作成して、CustomerCustomerAddress、および 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; }
}

プレゼンテーション モデルでの値のクエリと変更

プレゼンテーション モデルを作成した後、作成したプレゼンテーション モデルをクライアント プロジェクトに公開するには、プレゼンテーションの種類と対話するドメイン サービスを追加します。エンティティの値はこのドメイン サービスを介してのみ公開され、エンティティ全体を公開するドメイン サービスを介して公開されることはありません。次の例は、DomainService クラスから派生するドメイン サービスを示しています。

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

データを取得するには、ドメイン サービスにクエリ メソッドを追加します。クエリ メソッドで、データ アクセス層のエンティティから関連するデータを取得し、その値を、プレゼンテーション モデルの新しいインスタンス内の対応するプロパティに設定します。クエリ メソッドから、プレゼンテーション モデル型のインスタンス、またはジェネリック型が CustomerPresentationModel 型である IQueryable’1 を返します。次の例では、顧客のプレゼンテーション モデルのクエリ メソッドを示しています。

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

データ アクセス層の CustomerCustomerAddress、および Address の各エンティティはドメイン サービスによって公開されていないため、その型はクライアント プロジェクトでは生成されません。代わりに、CustomerPresentationModel 型のみがクライアント プロジェクトで生成されます。

プレゼンテーション モデルを使用してデータを更新するには、更新メソッドを作成し、プレゼンテーション モデルの値をエンティティに保存するためのロジックを定義します。更新メソッドの例は、次のセクションの最後に示します。

クライアントへの値の受け渡し

変更を送信した後、中間層ロジックまたはデータ ソースで設定されている値をクライアントに渡すことができます。RIA サービス には、エンティティの値をプレゼンテーション モデルに再度マップするための 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;
}