使用AutoMapper合并两个对象以生成第三个对象

时间:2010-03-17 14:47:40

标签: automapper

我知道它是AutoMapper而不是AutoMerge(r),但是......

我已经开始使用AutoMapper,需要映射A - > B,并从C中添加一些属性,使B成为A + C的一种平面复合。

这是否可以在AutoMapper中使用AutoMapper来进行繁重的工作然后手动映射额外的属性?

5 个答案:

答案 0 :(得分:14)

这不起作用吗?

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

答案 1 :(得分:13)

您可以使用ValueInjecter

执行此操作
 a.InjectFrom(b)
  .InjectFrom(c)
  .InjectFrom<SomeOtherMappingAlgorithmDefinedByYou>(dOrBOrWhateverObject);

答案 2 :(得分:5)

根据我对AutoMapper的记忆,您必须将映射定义为一个输出到一个输出(可能这已经改变了 - 一个月没有使用它)。

如果是这种情况,也许你的映射应该是KeyValuePair<A,C>(或某种对象组成A&amp; C)=&gt;乙

这样,您可以将一个已定义的输入参数映射到输出对象

答案 3 :(得分:5)

我在这个问题上进行了长时间的搜索并最终实现了将对象合并在一起的扩展方法。

我参考了我的博客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);

希望这有助于某人。

答案 4 :(得分:3)

有一个很好的例子,可以使用autoMapper将多个源合并到目标中,在Owain Wraggs中使用here&#39; EMC咨询博客。

编辑:防范旧的&#34; 死链接&#34;综合症,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);
    }