Объедините два объекта, чтобы создать третий, используя AutoMapper - PullRequest
26 голосов
/ 17 марта 2010

Я знаю, что это AutoMapper , а не AutoMerge (r), но ...

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

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

Ответы [ 5 ]

14 голосов
/ 21 апреля 2010

Разве это не сработает?

var mappedB = _mapper.Map<A,B>(aInstance);
_mapper.Map(instanceC,mappedB);
13 голосов
/ 05 мая 2010

Вы можете сделать это с помощью ValueInjecter

 a.InjectFrom(b)
  .InjectFrom(c)
  .InjectFrom<SomeOtherMappingAlgorithmDefinedByYou>(dOrBOrWhateverObject);
5 голосов
/ 19 сентября 2012

Я долго и усердно искал этот вопрос и в итоге реализовал метод расширения, который объединяет объекты.

Я ссылаюсь на шаги в моем блоге 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);

Надеюсь, это кому-нибудь поможет.

5 голосов
/ 17 марта 2010

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

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

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

4 голосов
/ 14 июня 2014

Хороший пример объединения нескольких источников в место назначения с использованием autoMapper, здесь в блоге EMC Consulting Оуэна Врагса.

РЕДАКТИРОВАТЬ: Для защиты от старого синдрома " 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);
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...