Подтвердить что ты не робот

Объедините два объекта для создания третьего с помощью AutoMapper

Я знаю его AutoMapper, а не AutoMerge (r), но...

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

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

4b9b3361

Ответ 1

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

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

Ответ 2

Неужели это не сработает?

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

Ответ 3

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

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

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

Ответ 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);

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

Ответ 5

Существует хороший пример объединения нескольких источников в пункт назначения с помощью autoMapper, здесь в Оуайн Wraggs' EMC Consulting блог.

РЕДАКТИРОВАТЬ: Для защиты от старого синдрома "мертвой связи" сущность кода в блоге Овайна ниже.

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