다음을 통해 공유


프레젠테이션 모델

WCF RIA Services를 사용하면 프레젠테이션 모델이라고 하는 데이터 액세스 계층의 여러 엔터티로부터 데이터를 집계하는 데이터 모델을 만들 수 있습니다. 데이터 액세스 계층의 엔터티를 클라이언트에 직접 노출하지 않으려는 경우 이 기능을 사용합니다. 프레젠테이션 모델을 사용할 때 클라이언트는 변경하지 않고 프레젠테이션 모델만 변경하여 데이터 액세스 계층의 변경 내용에 응답할 수 있습니다. 또한 클라이언트의 사용자와 관련된 필드만 집계하는 모델을 디자인하여 클라이언트 코드를 단순화할 수 있습니다. 이 항목에서는 프레젠테이션 모델을 만들고, 쿼리하고, 업데이트하는 방법과 중간 계층이나 데이터 소스에 변경 내용이 설정된 경우 클라이언트로 값을 다시 전달하는 방법에 대해 설명합니다.

프레젠테이션 모델 만들기

데이터 무결성을 유지하는 데 필요한 데이터베이스 구조는 클라이언트 응용 프로그램의 엔터티에 필요한 데이터베이스 구조보다 더 복잡할 수 있습니다. 응용 프로그램과 관련된 필드를 하나의 프레젠테이션 모델로 결합하여 이 데이터 구조를 단순화하는 프레젠테이션 모델을 만들 수 있습니다. 예를 들어, AdventureWorksLT 샘플 데이터베이스에서 Customer, CustomerAddressAddress 테이블을 통해 고객 및 주소 데이터를 검색합니다.

RS_CustomerEntities

서버 프로젝트에 클래스를 만들고 사용할 수 있게 하려는 속성을 정의하여 프레젠테이션 모델을 만듭니다. 정의하는 속성은 엔터티에서 노출하려는 속성과 일치합니다. 예를 들어, 서버 프로젝트에 다음 CustomerPresentationModel 클래스를 만들어 Customer, CustomerAddressAddress 테이블에서 원하는 필드만 표시할 수 있습니다.

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

데이터 액세스 계층의 (Customer, CustomerAddressAddress) 엔터티는 도메인 서비스에 의해 노출되지 않기 때문에 이러한 형식은 클라이언트 프로젝트에 생성되지 않습니다. 대신 CustomerPresentationModel 형식만 클라이언트 프로젝트에 생성됩니다.

프레젠테이션 모델을 통해 데이터를 업데이트하려면 업데이트 메서드를 만들고 프레젠테이션 모델의 값을 엔터티에 저장하는 논리를 정의합니다. 다음 단원 끝에 업데이트 메서드의 예제가 나와 있습니다.

클라이언트로 다시 값 전달

변경 내용을 전송한 후 중간 계층 논리나 데이터 소스에 설정된 값을 클라이언트로 다시 전달할 수 있습니다. RIA Services 에서는 엔터티의 값을 프레젠테이션 모델에 다시 매핑하는 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;
}