2010-03-17 64 views
22

我知道這是AutoMapper而不是AutoMerge(R),但...合併兩個對象產生第三使用AutoMapper

我使用AutoMapper起步,並沒有必要地圖A - > B,並添加從C的一些屬性,使B成爲A + C的一種扁平合成。

這是可能的AutoMapper的我應該只使用AutoMapper做繁重的工作,然後手動映射額外的屬性?

回答

4

從我記憶中的AutoMapper中,您必須將您的映射定義爲一個輸出的一個輸入(也許這已經改變 - 因爲一個月沒有使用它)。

如果是這種情況下,也許你的映射應該是KeyValuePair<A,C>(或某種物體的構成既甲& C)=>乙

這種方式可以具有一個定義的輸入參數映射到您的輸出對象

+0

複合物似乎是前進的方向,像使用現有的類太的想法 - 我給它一個嘗試。 –

+0

我們幾乎總是做一個B - > BDto。我們不斷遇到命名衝突的問題,以嘗試自動合併事件。 –

+0

我想對基於自動約定的方法進行映像確實很難(尤其是碰撞),但AutoMapper至少會允許您定義自己的函數/委託來用於映射,所以至少在這種情況下,手動做...並且它也不需要太多代碼 - 爲漂亮的實用程序拍攝! :) – saret

12

這不行嗎?

var mappedB = _mapper.Map<A,B>(aInstance); 
_mapper.Map(instanceC,mappedB); 
+16

我不知道 - 是嗎? –

14

您可以用ValueInjecter

a.InjectFrom(b) 
    .InjectFrom(c) 
    .InjectFrom<SomeOtherMappingAlgorithmDefinedByYou>(dOrBOrWhateverObject); 
+4

這個工具很酷。 – Merritt

+0

現在使用它將一堆不同的類似dto的對象映射到一個EF實體。 – Merritt

+1

@歐姆,非常有趣的工具,但我不確定,如果你回答上面的問題,但。 – hgulyan

4

我搜索艱辛而漫長的這個問題,並最終實現一個的對象合併在一起的擴展方法做到這一點。

我引用的步驟在我的博客http://twistyvortek.blogspot.com和下面的代碼:

 

    using System; 

    namespace Domain.Models 
    { 
     public static class ExtendedMethods 
     { 
      /// <summary> 
      /// Merges two object instances together. The primary instance will retain all non-Null values, and the second will merge all properties that map to null properties the primary 
      /// </summary> 
      /// <typeparam name="T">Type Parameter of the merging objects. Both objects must be of the same type.</typeparam> 
      /// <param name="primary">The object that is receiving merge data (modified)</param> 
      /// <param name="secondary">The object supplying the merging properties. (unmodified)</param> 
      /// <returns>The primary object (modified)</returns> 
      public static T MergeWith<T>(this T primary, T secondary) 
      { 
       foreach (var pi in typeof (T).GetProperties()) 
       { 
        var priValue = pi.GetGetMethod().Invoke(primary, null); 
        var secValue = pi.GetGetMethod().Invoke(secondary, null); 
        if (priValue == null || (pi.PropertyType.IsValueType && priValue == Activator.CreateInstance(pi.PropertyType))) 
        { 
         pi.GetSetMethod().Invoke(primary, new[] {secValue}); 
        } 
       } 
       return primary; 
      } 
     } 
    } 

用途包括方法鏈接,所以你可以合併多個對象爲一。

我會做的是使用automapper將來自各種源的部分屬性映射到相同類的DTO等,然後使用此擴展方法將它們合併在一起。

 

    var Obj1 = Mapper.Map(Instance1); 
    var Obj2 = Mapper.Map(Instance2); 
    var Obj3 = Mapper.Map(Instance3); 
    var Obj4 = Mapper.Map(Instance4); 

    var finalMerge = Obj1.MergeWith(Obj2) 
           .MergeWith(Obj3) 
           .MergeWith(Obj4); 

希望這可以幫助別人。

+1

我非常確定這不會編譯,定義擴展方法的類必須是非泛型的和靜態的,那麼MergeWith(這個T primary,T secondary)如何纔能有效? – SimonGates

+0

該類是非泛型和靜態的。這是通用的方法,但這不是問題。 –

+3

public static T MergeWith (此T小學,T中學) –

3

在Owain Wraggs的EMC諮詢博客中,有一個使用autoMapper,here將多個源合併到目的地的好例子。

編輯:爲了防範舊的「死鏈接」症候羣,Owain的博客中的代碼的本質如下。

/// <summary> 
/// Helper class to assist in mapping multiple entities to one single 
/// entity. 
/// </summary> 
/// <remarks> 
/// Code courtesy of Owain Wraggs' EMC Consulting Blog 
/// Ref: 
///  http://consultingblogs.emc.com/owainwragg/archive/2010/12/22/automapper-mapping-from-multiple-objects.aspx 
/// </remarks> 
public static class EntityMapper 
{ 
    /// <summary> 
    /// Maps the specified sources to the specified destination type. 
    /// </summary> 
    /// <typeparam name="T">The type of the destination</typeparam> 
    /// <param name="sources">The sources.</param> 
    /// <returns></returns> 
    /// <example> 
    /// Retrieve the person, address and comment entities 
    /// and map them on to a person view model entity. 
    /// 
    /// var personId = 23; 
    /// var person = _personTasks.GetPerson(personId); 
    /// var address = _personTasks.GetAddress(personId); 
    /// var comment = _personTasks.GetComment(personId); 
    /// 
    /// var personViewModel = EntityMapper.Map<PersonViewModel>(person, address, comment); 
    /// </example> 
    public static T Map<T>(params object[] sources) where T : class 
    { 
     // If there are no sources just return the destination object 
     if (!sources.Any()) 
     { 
      return default(T); 
     } 

     // Get the inital source and map it 
     var initialSource = sources[0]; 
     var mappingResult = Map<T>(initialSource); 

     // Now map the remaining source objects 
     if (sources.Count() > 1) 
     { 
      Map(mappingResult, sources.Skip(1).ToArray()); 
     } 

     // return the destination object 
     return mappingResult; 
    } 

    /// <summary> 
    /// Maps the specified sources to the specified destination. 
    /// </summary> 
    /// <param name="destination">The destination.</param> 
    /// <param name="sources">The sources.</param> 
    private static void Map(object destination, params object[] sources) 
    { 
     // If there are no sources just return the destination object 
     if (!sources.Any()) 
     { 
      return; 
     } 

     // Get the destination type 
     var destinationType = destination.GetType(); 

     // Itereate through all of the sources... 
     foreach (var source in sources) 
     { 
      // ... get the source type and map the source to the destination 
      var sourceType = source.GetType(); 
      Mapper.Map(source, destination, sourceType, destinationType); 
     } 
    } 

    /// <summary> 
    /// Maps the specified source to the destination. 
    /// </summary> 
    /// <typeparam name="T">type of teh destination</typeparam> 
    /// <param name="source">The source.</param> 
    /// <returns></returns> 
    private static T Map<T>(object source) where T : class 
    { 
     // Get thr source and destination types 
     var destinationType = typeof(T); 
     var sourceType = source.GetType(); 

     // Get the destination using AutoMapper's Map 
     var mappingResult = Mapper.Map(source, sourceType, destinationType); 

     // Return the destination 
     return mappingResult as T; 
    } 
} 

由此產生的調用代碼是很好的簡潔。

public ActionResult Index() 
    { 

     // Retrieve the person, address and comment entities and 
     // map them on to a person view model entity 
     var personId = 23; 

     var person = _personTasks.GetPerson(personId); 
     var address = _personTasks.GetAddress(personId); 
     var comment = _personTasks.GetComment(personId); 

     var personViewModel = EntityMapper.Map<PersonViewModel>(person, address, comment); 

     return this.View(personViewModel); 
    }