2010-07-14 3 views
3

WCF 서비스 응용 프로그램에 비즈니스 수준 개체 계층과 계약 수준 개체 계층이 있습니다. 언급하고있는 비즈니스 계층 객체는 데이터를 보관하는 데 사용하는 엔티티 또는 POCO 객체입니다. 제가 언급하고있는 계약 수준 객체는 내 클라이언트가 보는 WSDL을 구성하는 객체입니다 (POCO도 포함).디자인 질문 한 계층의 POCO를 다른 계층의 POCO로 변환하는 방법

내 WCF 서비스에서 클라이언트로 데이터를 반환하면 요청 매개 변수가 내 계약 계층 개체 중 하나 이상에서 XML로 수화되고 전달됩니다.

하나의 레이어에서 다른 레이어로 개체를 변환하는 계약 및 비즈니스 계층 외부에있는 클래스를 만들려고합니다. 그 재산의 속성에 매핑 될 비즈니스 계층에서 (또는 다른 수)

public class Person 
{ 
    public string Name { get; set;}; 
} 

가 나는 또한 동일한 클래스를 할 수 : 그래서, 예를 들어, 계약 층에서 내가 좋아하는 클래스를 가질 것 이 클래스. 예상대로

public Contract.Person TranslatePerson(Business.Person person) 
{ 
    Contract.Person result = new Contract.Person(); 
    result.Name = person.Name; 
    return result; 
} 

이 모든 작품 :

나는 다음과 같습니다 코드를 실행하는 클래스가 있습니다. 그러나이 변환기 서비스의 요구 사항 중 하나는 계약 계층의 변경 사항으로부터 비즈니스 계층을 격리하는 것이고이 계층의 요구 사항 중 하나는 SOAP 클라이언트에 대한 하위 호환성을 지원하기 위해 서로 다른 버전의 계약 계층이 동시에 존재할 수 있도록하는 것입니다 . 이제 때

// remains for backwards compatibility for V1 clients 
namespace Contract.V1 
{ 
    public class Person 
    { 
     public string Name { get; set;}; 
    } 
} 

namespace Contract.V2 
{ 
    public class Person 
    { 
     public string FirstName { get; set;}; 
     public string LastName { get; set;}; 
    } 
} 

: 예를 들어 서비스의 V2에 나는 이런 식으로 뭔가를해야합니다 나의 SOAP 클라이언트는 이제 모두의 데이터를 볼 수 있도록 사람 클래스에 마지막으로 이름을 추가하고 FIRSTNAME로 이름을 변경하려면 비즈니스 개체에서 성과 이름을성에 매핑하려는 클라이언트에게 V2 Person을 다시 보내야합니다. 그러나 V1 Person을 다시 보내야하는 경우 FirstName을 Name으로 매핑하고 LastName을 삭제합니다.

내 번역 레이어 생성 된 아키텍처는 thusly 히입니다 : 내가 V1Translator 100 개 다른 번역 방법이있을 수 있지만 난 단지에 2 또는 3를 오버라이드 (override) 할 수 있기 때문에

public class V1Translator 
{ 
    public virtual Contract.V1.Person TranslatePerson(Business.Person person) 
    { 
     Contract.V1.Person result = new Contract.V1.Person(); 
     result.Name = person.Name; 
     return result; 
    } 
} 

public class V2Translator : V1Translator 
{ 
    public override Contract.V2.Person TranslatePerson(Business.Person person) 
    { 
     Contract.V2.Person result = new Contract.V2.Person(); 
     result.Name = person.Name; 
     return result; 
    } 
} 

이 나에게 많은 시간을 절약 V2Translator는 다른 레이어에서 변경되는 개체가 몇 개 밖에 없기 때문에 가능합니다. 팩토리를 사용하여 적절한 Translator 클래스를 인스턴스화합니다. 이 방식으로 나는 특별한 TranslationService 클래스에서 TranslatePerson을 호출하고 사용할 Translator를 알아낼 수 있습니다. 그러나 이것은 문제가 발생하는 곳이기도합니다. 반환 형식이 다르므로 기본 클래스의 메서드를 재정의 할 수 없습니다. 둘 다 Contract Person 객체이지만 서로 다른 네임 스페이스에 있습니다. 나는 이것을 통과하는 데 어려움을 겪고있다.

누군가이 문제에 대한 우아한 해결책을 제시 할 수 있습니까?

감사

답변

0

체크 아웃 AutoMapper, 당신이이 같은 시나리오에서 작성해야 수동 매핑 코드의 양을 줄이는 우수한입니다.

+0

에 (따라서 IActiveRecord 제약) 아음속 2 엔티티를 변환하는 데 사용합니다. 나는의 단조 로움을 처리하기 위해 무엇을 찾고 있었다 것 같은데 객체 매핑. – omatase

0

나는이 정확한 문제를 해결하기 위해이 2 가지 확장 방법을 작성 했으므로 문제를 해결하기위한 좋은 출발점을 제공 할 수 있습니다.

public static Y To<X, Y>(this X source) where X : IActiveRecord where Y: class 
{ 
    try 
    { 
     Y target = Activator.CreateInstance(typeof(Y)) as Y; 

     BindingFlags memberAccess = BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.SetProperty; 

     PropertyInfo[] targetProperties = target.GetType().GetProperties(memberAccess); 
     foreach (MemberInfo Field in targetProperties) 
     { 
      string name = Field.Name; 

      if (Field.MemberType == MemberTypes.Property) 
      { 
       PropertyInfo targetProperty = Field as PropertyInfo; 
       PropertyInfo sourceProperty = source.GetType().GetProperty(name, memberAccess); 

       if (sourceProperty == null) { continue; } 

       if (targetProperty.CanWrite && sourceProperty.CanRead) 
       { 
        object targetValue = targetProperty.GetValue(target, null); 
        object sourceValue = sourceProperty.GetValue(source, null); 

        if (sourceValue == null) { continue; } 

        if (targetProperty.PropertyType.FullName == sourceProperty.PropertyType.FullName) 
        { 
         object tempSourceValue = sourceProperty.GetValue(source, null); 
         targetProperty.SetValue(target, tempSourceValue, null); 
        } 
       } 
      } 
     } 

     return target; 
    } 
    // it's important to return null if there are any errors. 
    catch { return null; } 
} 


public static IList<Y> To<X, Y>(this BindingListEx<X> collection) where X : IActiveRecord where Y : class 
{ 
    IList<Y> returnList = new List<Y>(); 

    foreach (X item in collection) 
     returnList.Add(item.To<X,Y>()); 

    return returnList; 
} 

이 난 단지 내가 어제 :(봤다면이 내 자신의 POCO의

관련 문제