[英]How to use AutoMapper to map destination object with a child object in the source object?
I have the source and destination objects like this: 我有这样的源和目标对象:
class ProductWithCategories // Source class
{
public Product Product { get; set; } // Product is an EF entity class
public IEnumerable<Category> Categories { get; set; }
}
class ProductViewModel // Dest class
{
public int Id { get; set; }
// Other properties with the same name as Product class
public IEnumerable<CategoryViewModel> Categories { get; set; }
}
So, my need is to map the values of source.Product
into dest
, and then source.Categories
into dest.Categories
. 所以,我需要的是的值映射
source.Product
到dest
然后和source.Categories
到dest.Categories
。 Is it possible with AutoMapper? AutoMapper有可能吗?
I have tried this and I was not surprised when it failed: 我试过这个,当它失败时我并不感到惊讶:
config.CreateMap<ProductWithCategories, ProductViewModel>()
.ForMember(q => q, option => option.MapFrom(q => q.Product))
.ForMember(q => q.Categories, option => option.MapFrom(q => q.Categories));
Here is the exception I received: 以下是我收到的例外情况:
[AutoMapperConfigurationException: Custom configuration for members is only supported for top-level individual members on a type.]
[AutoMapperConfigurationException:成员的自定义配置仅支持某个类型的顶级个人成员。]
After some discussion with OP, it turns out his main need is to quickly map a child/nested object inside the source object to the flattened destination object. 在与OP讨论之后,事实证明他的主要需求是快速将源对象内的子/嵌套对象映射到展平的目标对象。 He does not want to write a mapping for every property of the destination.
他不想为目的地的每个属性编写映射。
Here is a way to achieve this: 这是实现此目的的一种方法:
Product
-> ProductViewModel
used to flatten the members of Product Product
- > ProductViewModel
用于展平Product的成员 Category
to CategoryViewModel
Category
定义为CategoryViewModel
Define a mapping ProductWithCategories
-> ProductViewModel
that maps the categories, and then in the aftermap, map the Product
: 定义一个映射
ProductWithCategories
- > ProductViewModel
,它映射类别,然后在aftermap中映射Product
:
config.CreateMap<ProductWithCategories, ProductViewModel>() .ForMember(q => q.Id, option => option.Ignore()) // flattened in AfterMap .ForMember(q => q.Categories, option => option.MapFrom(q => q.Categories)) .AfterMap((src, dst) => Mapper.Map(src.Product, dst));
Using recent versions of AutoMapper, you can do something like the following: 使用最新版本的AutoMapper,您可以执行以下操作:
config.CreateMap<Product, ProductViewModel>()
.ForMember(q => q.Categories, option => option.Ignore());
config.CreateMap<ProductWithCategories, ProductViewModel>()
.ConstructUsing(s => AutoMapper.Mapper.Map<ProductViewModel>(s.Product))
.ForMember(q => q.Categories, option => option.MapFrom(q => q.Categories))
.ForAllOtherMembers(o => o.Ignore();
ConstructUsing() is used to generate and populate the base class from the nested child[ren] of the source. ConstructUsing()用于从源的嵌套子[ren]生成和填充基类。 If you have more than one such nested child, you would need to make several mapping calls to map each of them successively onto the instance generated by the first Map() call.
如果您有多个这样的嵌套子级,则需要进行多次映射调用,将其中的每一个连续映射到第一次Map()调用生成的实例上。 The .ForAllOtherMembers() is relatively recent (if you don't have it, get a newer version of AutoMapper.) Unfortunately it's slightly unsafe as if you add destination members which will need mapping but forget to update the map, configuration validation will not catch it.
.ForAllOtherMembers()是相对较新的(如果您没有它,请获取更新版本的AutoMapper。)不幸的是,它稍微不安全,就好像您添加了需要映射但忘记更新地图的目标成员,配置验证不会抓住它。
you should do like - 你应该喜欢 -
AutoMapper.Mapper.CreateMap<Category, CategoryViewModel>();
AutoMapper.Mapper.CreateMap<ProductWithCategories, ProductViewModel>()
.ForMember(a => a.Id, b => b.ResolveUsing(c => c.Product != null ? c.Product.MyProperty : 0))
.ForMember(a => a.Categories, b => b.ResolveUsing(c => c.Categories));
But it is better to wrap those properties from ProductViewModel
(props like Id
) inside another class. 但最好将
ProductViewModel
(像Id
这样的道具)中的那些属性包装在另一个类中。 And create another map for things to work automapper way. 并创建另一个地图,使事物以自动播放方式工作。
The offending line that generates the error is 产生错误的违规行是
.ForMember(q => q, option => option.MapFrom(q => q.Product))
The error message is hard to understand, but it means you have to state the destination properties explicitly: 错误消息很难理解,但这意味着您必须明确声明目标属性:
.ForMember(q => q.Id, option => option.MapFrom(q => q.Product.Id))
.ForMember(q => q.OtherProperty, option => option.MapFrom(q => q.Product.OtherProperty))
You also have to define a mapping from Category
to CategoryViewModel
for 您还必须定义从
Category
到CategoryViewModel
的映射
.ForMember(q => q.Categories, option => option.MapFrom(q => q.Categories))
to work: 上班:
config.CreateMap<Category, CategoryViewModel>();
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.