2010-07-14 89 views
3

具有商業級對象的一個​​層,並在WCF服務應用合同級對象的層。我所指的業務層對象只是我用來存放數據的實體或POCO對象。我指的合同級別對象是組成客戶看到的WSDL(也包括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客戶端的向後兼容性。例如,如果在服務的V2我想最後的名稱添加到個人類和更改名稱名字,使我的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 Person發送回客戶端,我想將FirstName從業務對象映射到FirstName並將LastName映射到LastName。但是,如果我需要發回一個V1 Person,我會將FirstName映射到名稱,並放棄LastName。

我爲我的翻譯層產生的建築正是如此:

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

這爲我節省了很多時間,因爲我有可能在V1Translator 100種不同的翻譯方法,但我可能只需要覆蓋2或3 V2Translator,因爲在不同層次中可能只有少數幾個對象發生變化。我也使用工廠實例化相應的Translator類。通過這種方式,我可以在我的特殊翻譯服務類上調用TranslatePerson,並確定要使用哪個翻譯器。但是,這也是問題出現的地方。我無法重寫基類中的方法,因爲返回類型不同。儘管它們都是Contract Person對象,但它們位於不同的名稱空間中。我很難通過這個。

有人可以幫我創建一個優雅的解決這個問題?

感謝

回答

0

退房AutoMapper,這是非常好的減少手動映射代碼,你需要在這樣的情況下寫的金額。

+0

如果我昨天:(看到了。看起來像什麼,我一直在尋找處理的單調對象映射。 – omatase 2010-07-15 00:44:12

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

我用這個轉換亞音速2個實體(因此IActiveRecord約束),以我自己的POCO的