如何使用automapper 9.0.0.0

时间:2019-08-14 07:55:34

标签: c# automapper

我试图基于Handle属性使用automapper自动映射两个列表。类似于内部联接。使用automapper 9.0.0.0可以做到吗?

public class MyObject
{
    public int Handle { get; set; }
    public string Name { get; set; }
}

public class MyObjectExtension
{
    public int Handle { get; set; }
    public string Description{ get; set; }
}

public class MyRichObject
{
    public int Handle { get; set; }
    public string Name { get; set; }
    public string Description{ get; set; }
}

//and here my mapper usage:

IEnumerable<MyObject> MyObjects;
IEnumerable<MyObjectExtension> MyObjectExtensions;
IEnumerable<MyRichObject> MyRichObjects;

// mapping to a new object
MyRichObjects= Mapper.Map<IEnumerable<MyRichObject>(MyObjects);

// adding MyObjectExtension properties by mapping to the existing RichObject
MyRichObjects= Mapper.Map<IEnumerable<MyObjectExtension>, IEnumerable<MyRichObject>>(MyObjectExtensions, MyRichObjects);

这最后的代码有效,但是它可能一个一个地映射两个列表中的元素,我想基于Handle属性来映射它们。

这是我在NInjectDependencyResolver类中为NInject添加Automapper绑定的方法,但是如何设置cfg.AddCollectionMappers()?



            // AutoMapper mapping  
            kernel.Bind<MapperConfiguration>()
                  .ToSelf()
                  .WithConstructorArgument<Action<IMapperConfigurationExpression>>(
                        cfg => new Mappers.AutoMapperConfiguration(cfg));
                  //.InRequestScope()
            kernel.Bind<IConfigurationProvider>().ToMethod(ctx => ctx.Kernel.Get<MapperConfiguration>());
            kernel.Bind<IMapper>().ToMethod(maper => kernel.Get<MapperConfiguration>().CreateMapper()).InSingletonScope();
            kernel.Bind<IExpressionBuilder>().ToConstructor(ctx => new ExpressionBuilder(kernel.Get<MapperConfiguration>()));

2 个答案:

答案 0 :(得分:3)

AutoMapper 9删除了静态映射,因此仅当Mapper是一个IMapper属性或包含对映射器实例的引用的字段时,该问题的代码才能工作。

the AutoMapper docs说:

  

映射到现有集合时,将首先清除目标集合。如果这不是您想要的,请查看AutoMapper.Collection

库的Github页面显示,按句柄匹配需要将Collections添加到映射器配置中,并用单行指定对象等效项:

cfg.AddCollectionMappers();
...
cfg.CreateMap<MyObjectExtension, MyRichObject>()
   .EqualityComparison( (oe, ro) => oe.Handle == ro.Handle);

之后,您可以直接调用Map,而无需进行任何修改:

mapper.Map(MyObjectExtensions, MyRichObjects);

这与LINQ Join非常相似。实际上,mapping implementationEnumerable.Join's implementation非常相似-两种方法都创建目标的Lookup表,以在遍历源代码之前加快查找速度。 AutoMapper进一步走了一步,并使用匹配的源属性更新目标对象。

请注意,destination必须是ICollection<T>。它不能是IEnumerable<T>,因为该界面不允许修改。

一种替代方法是在MyObjectsMyObjectExtensions之间使用LINQ连接:

var richObjects=myObjects.Join(myObjectsExtensions,
                               o  => o.Handle,
                               oe => oe.Handle,
                               (o,oe)=>new MyRichObject {
                                           Handle      = o.Handle, 
                                           Name        = o.Name,
                                           Description = oe.Description
                                       })
                          .ToArray();

重要

如果数据已经在内存中,那么所有这些都是有意义的。对于存储在数据库中的数据,使用JOIN执行SQL语句的时间更快,更便宜(更容易),并且可以直接返回最终对象。该查询可以由EF(核心)之类的ORM生成,也可以由Dapper之类的微型ORM直接执行。

答案 1 :(得分:1)

对于您而言,我认为最好使用Linq。 例如:

        List<MyObject> listMyObject = new List<MyObject>();
        listMyObject.Add(new MyObject() { Handle = 1, Name = "FirstName" });
        listMyObject.Add(new MyObject() { Handle = 2, Name = "SecondName" });
        listMyObject.Add(new MyObject() { Handle = 3, Name = "ThirdName" });


        List<MyObjectExtension> listMyObjectExtensions = new List<MyObjectExtension>();
        listMyObjectExtensions.Add(new MyObjectExtension() { Handle = 1, Description = "FirstDescription" });
        listMyObjectExtensions.Add(new MyObjectExtension() { Handle = 2, Description = "SecondDescription" });
        listMyObjectExtensions.Add(new MyObjectExtension() { Handle = 3, Description = "ThirdDescription" });


        IEnumerable<MyObject> MyObjects = listMyObject.AsEnumerable<MyObject>();
        IEnumerable<MyObjectExtension> MyObjectExtensions = listMyObjectExtensions.AsEnumerable<MyObjectExtension>();
        IEnumerable<MyRichObject> MyRichObjects;

        MyRichObjects = from myObject in MyObjects
                    join myObjectExtension in MyObjectExtensions on myObject.Handle equals myObjectExtension.Handle
                    select new MyRichObject { Handle = myObject.Handle, Name = myObject.Name, Description = myObjectExtension.Description };



        foreach (var MyRichObject in MyRichObjects)
        {
            System.Diagnostics.Debug.WriteLine($"Id: \"{MyRichObject.Handle}\". Name: {MyRichObject.Name}  Description: {MyRichObject.Description}");
        }

返回:

 Id: "1". Name: FirstName  Description: FirstDescription
 Id: "2". Name: SecondName  Description: SecondDescription
 Id: "3". Name: ThirdName  Description: ThirdDescription