2010-03-17 2 views
22

Я знаю, что это AutoMapper и не AutoMerge (г), но ...Объединение двух объектов для получения третьего использования AutoMapper

Я начал использовать AutoMapper и есть необходимость Карты A -> B, и добавить некоторые свойства из C, чтобы B стал своего рода плоским композитом A + C.

Возможно ли это в AutoMapper, следует ли использовать AutoMapper для тяжелого подъема, а затем вручную сопоставить дополнительные свойства?

ответ

4

Из того, что я помню с помощью AutoMapper, вы должны определить свои сопоставления как один вход на один вывод (возможно, это изменилось с тех пор, - он не использовал его много месяцев).

Если это так, то, может быть, ваше отображение должно быть KeyValuePair<A,C> (или какого-то объекта, составляющего как A & C) => B

Таким образом, вы можете иметь один определенный отображение входного параметра для вашего выводимого объекта

+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

@Omu, очень интересный инструмент, купите, я не уверен, если вы ответили на вопрос выше. – 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

Есть хороший пример слияния нескольких источников в пункт назначения с использованием autoMapper, here в блоге EMC Consulting Owain Wraggs.

EDIT: Для защиты от старого «dead-link» синдром, суть кода в блоге Овайна ниже.

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