2013-12-13 32 views
3

編輯:這原本是1:1映射,但我想通了,我需要一個更復雜的遞歸映射,這樣一個新的問題被張貼在這裏:How to recursively map entity to view model with Automapper function call?如何自動將.NET函數調用映射到屬性?

我想一般映射實體類功能到視圖模型,使用ServiceStack ConvertTo <>方法。這映射所有相似的類型和屬性名稱,並且工作正常,但我想找到一種方法將函數的結果映射到屬性。下面是一些代碼

實體例如:

public class Item { 
    public long Id {get; set;} 
    public List<Product> GetProducts() { 
      return Repository.GetAll<Product>(); 
    } 
} 

視圖模型例如:

public class ItemViewModel { 
    public long Id {get;set;} 
    public List<Product> Products {get; set;} 
} 

理想的結果將是有一個地圖功能,着眼於實體類的匹配方法返回類型,函數名稱是「Get」+屬性名稱,然後執行它並將結果映射到視圖模型。

public TTarget MapToViewModel<TSource, TTarget>(TSource source) 
    where TTarget : new() 
{ 
    var sourceType = source.GetType(); 

    var targetProperties = typeof(TTarget).GetProperties(BindingFlags.Public | BindingFlags.Instance); 

    var sourceProperties = sourceType.GetProperties(BindingFlags.Public | BindingFlags.Instance); 
    var sourceMethods = sourceType.GetMethods(BindingFlags.Public | BindingFlags.Instance); 

    var target = Activator.CreateInstance<TTarget>(); 

    foreach (var prop in targetProperties) 
    { 
     var sourceProp = sourceProperties.FirstOrDefault(x => x.Name == prop.Name); 
     if (sourceProp != null) 
     { 
      prop.SetValue(target, sourceProp.GetValue(source, null), null); 
     } 
     else 
     { 
      var sourceMethod = sourceMethods.FirstOrDefault(x => x.Name == "Get" + prop.Name); 
      if (sourceMethod != null) 
      { 
       prop.SetValue(target, sourceMethod.Invoke(source, null), null); 
      } 
     } 
    } 

    return target; 
} 

在上面的.FirstOrDefault調用的條件:

回答

2

雖然你也許能找到類似AutomapperValue Injecter可能已經包含了此功能,還有從編寫一個小巧的實用方法阻止你什麼只需使用Name,但您可以將它們擴展到任何你喜歡的。

要使用此功能,只需要調用它像這樣:

var itemViewModel = MapToViewModel<Item, ItemViewModel>(item); 

只是要小心,如果你在你的常規模型的方法的任何參數。如果你發現你的模型太複雜了(或者不遵循一個或兩個命名約定),那麼使用AutoMapper之類的東西可能會更好。但對於簡單的映射,這樣的事情應該能夠完成這項工作。

+0

謝謝,我得到了這個工作。現在我有另一個困境。做這個遞歸有多難?例如,如果Product類有一個屬性List 圖像,我需要從Product類調用GetImages()? – user3092978

+0

我真的沒有看到這將需要一個遞歸調用。你的意思是,如果方法和屬性都存在於一個對象上,那麼該方法需要調用?如果是這樣的話,你可以切換屬性和方法的if語句來首先檢查方法。 – valverij

+0

不完全,我的意思是如果映射對象具有需要通過調用另一個函數來映射的另一個屬性。你的回答幫助我確定我需要一些更復雜的東西,看起來像Automapper可能能夠處理。我問另一個問題在這裏http://stackoverflow.com/questions/20573600/how-to-recursively-map-entity-to-view-model-with-automapper-function-call – user3092978

1

使用ServiceStack進行映射將非常難以制定一個通用解決方案,因爲您基本上必須自己編寫代碼以將Products與匹配。

您可以使用另一個映射庫,如AutoMapper,它會自動使用GetX()來填充X

// one time config 
Mapper.CreateMap<Item, ItemViewModel>(); 
Mapper.AssertConfigurationIsValid(); 

// whenever you map 
Item item = // whatever 
ItemViewModel viewModel = Mapper.Map<ItemViewModel>(item); 
// viewModel.Products is populated from item.GetProducts() 

手動改變特定事物的映射方式也很容易,例如,你可以手動設置這個使用這個CreateMap

Mapper.CreateMap<Item, ItemViewModel>() 
    .ForMember(dest => dest.Products, 
         opt => opt.ResolveUsing(src => src.GetProducts())); 

它看起來像AutoMapper是一個更強大的映射。即使您對其他部分使用ServiceStack,爲您的映射使用AutoMapper可能也是值得的。

+0

不錯,我想AutoMapper可以做這樣的事情(即使它只是使用'.AfterMap'功能) – valverij

+0

不錯,我沒有考慮Automapper。 Automapper是否會遞歸地支持這個? – user3092978

+0

是的(我認爲;不確定你的意思是「遞歸」),例如如果'Products'和'GetProducts'返回不同的類型,但在這兩種產品類型之間創建了一個映射(例如'Mapper.CreateMap ();'),它也會自動映射這些項目。 –

相關問題