c# - 如何使用 automapper 9.0.0.0 根据句柄属性自动映射两个列表
问题描述
我正在尝试使用基于 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>()));
解决方案
AutoMapper 9 删除了静态映射,因此问题的代码只有Mapper
在IMapper
属性或字段持有对映射器实例的引用时才能工作。
正如AutoMapper 文档所说:
映射到现有集合时,首先清除目标集合。如果这不是您想要的,请查看AutoMapper.Collection。
该库的 Github 页面显示,按句柄进行匹配需要添加Collections
到映射器配置并使用单行指定对象等效性:
cfg.AddCollectionMappers();
...
cfg.CreateMap<MyObjectExtension, MyRichObject>()
.EqualityComparison( (oe, ro) => oe.Handle == ro.Handle);
之后,您可以直接调用Map
而无需任何修改:
mapper.Map(MyObjectExtensions, MyRichObjects);
这与 LINQ Join 非常相似。事实上,映射实现与Enumerable.Join 的实现非常相似——这两种方法都创建一个Lookup
目标表以在迭代源之前加快查找速度。AutoMapper 更进一步,并使用匹配的源属性更新目标对象。
请注意,destination
它必须是一个ICollection<T>
. 它不能是,IEnumerable<T>
因为该接口不允许修改。
MyObjects
另一种方法是在and之间使用 LINQ 连接MyObjectExtensions
:
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 (Core) 这样的 ORM 生成,也可以由像 Dapper 这样的微 ORM 直接执行。
推荐阅读
- laravel - 观察员未填写该字段
- r - 如何在R中解决“二元运算符的非数字参数”?
- regex - 如何使用 2 种不同模式获取第 n 次出现之间的所有字符串
- python - 未指定类型的编码字段;无法自动推断类型,因为数据未指定为 pandas.DataFrame
- angular - Angular HttpErrorResponse net::ERR_HTTP2_PROTOCOL_ERROR
- nuxt.js - 我可以在导航而不是在生成执行期间执行 nuxt asyndata 挂钩吗?
- javascript - 在个人网站上发布谷歌博客现货博客
- qt - 将事件传播到整个对象
- java - Java slackbot - 未处理的异常错误
- reactjs - 带有 React Router 的 React-bootstrap 导航栏