[英]AutoMapper: Map to collection from multiple source properties
UPDATE April 13th, 2018 : Automapper 6.1.0 supports unflattening by introducing ReverseMap
. 更新2018年4月13日 :Automapper 6.1.0通过引入ReverseMap
支持ReverseMap
。 See release notes here 在此处查看发行说明
I'm trying to use AutoMapper to unflatten an object. 我正在尝试使用AutoMapper展开对象。
I have a source as follows 我有以下来源
public class Source
{
public string Name {get;set;}
public string Child1Property1 {get;set;}
public string Child1Property2 {get;set;}
public string Child2Property1 {get;set;}
public string Child2Property2 {get;set;}
}
I want to map to this to destination 我想映射到目的地
public class Destination
{
public string Name {get;set;}
public List<Child> Children {get;set;}
}
public class Child
{
public string Property1 {get;set;}
public string Property2 {get;set;}
}
My mapping configuration 我的映射配置
public static class AutoMapperConfiguration
{
public static MapperConfiguration Configure()
{
var config = new MapperConfiguration(
cfg =>
{
cfg.CreateMap<Source, Destination>()
.ForMember(dest => dest.Children, /* What do I put here?*/))
// I don't think this is correct
cfg.CreateMap<Source, Child>()
.ForMember(dest => dest.Property1, opt => opt.MapFrom(src => src.Child1Property1))
.ForMember(dest => dest.Property2, opt => opt.MapFrom(src => src.Child1Property2))
.ForMember(dest => dest.Property1, opt => opt.MapFrom(src => src.Child2Property1))
.ForMember(dest => dest.Property2, opt => opt.MapFrom(src => src.Child2Property2));
});
return config;
}
}
Now when I test my code I get using mapper.Map<List<Child>>(source)
I get a AutoMapperMappingException: Missing type map configuration or unsupported mapping.
现在,当我测试代码时,我使用了mapper.Map<List<Child>>(source)
我得到了AutoMapperMappingException: Missing type map configuration or unsupported mapping.
Which make sense, since there isn't a mapping configured to a List<Child>
. 这很有意义,因为没有配置为List<Child>
的映射。 If I do mapper.Map<Child>(source)
, I get a Child
instance with all null
values for the properties. 如果执行mapper.Map<Child>(source)
, mapper.Map<Child>(source)
获得一个Child
实例,该实例的所有属性都为null
。
I'm unfortunately not in a position to modify the Source
class. 不幸的是,我无法修改Source
类。
Is this possible at all with AutoMapper? AutoMapper完全可以做到吗? and if so how? 如果可以,怎么办?
There are at least 2 options. 至少有2个选项。 You can use a simple extension method to simplify the mapping or you can create a custom type converter. 您可以使用简单的扩展方法来简化映射,也可以创建自定义类型转换器。
public class ConvertSourceToDestination : ITypeConverter<Source, Destination>
{
public Destination Convert(Source source, Destination destination, ResolutionContext context)
{
destination = destination ?? new Destination();
destination.Children = destination.Children ?? new List<Child>();
destination.Children.Add(new Child() { Property1 = source.Child1Property1, Property2 = source.Child1Property2 });
destination.Children.Add(new Child() { Property1 = source.Child2Property1, Property2 = source.Child2Property2 });
destination.Name = source.Name;
return destination;
}
}
public static class SourceExtension
{
public static IEnumerable<Child> Children(this Source source)
{
yield return new Child() { Property1 = source.Child1Property1, Property2 = source.Child1Property2 };
yield return new Child() { Property1 = source.Child2Property1, Property2 = source.Child2Property2 };
}
public static MapperConfiguration CreateMapping()
{
var config = new MapperConfiguration(
cfg =>
{
cfg.CreateMap<Source, Destination>()
.ForMember(dest => dest.Children, opt => opt.MapFrom(src => src.Children()));
});
return config;
}
public static MapperConfiguration CreateMapping2()
{
var config = new MapperConfiguration(
cfg =>
{
cfg.CreateMap<Source, Destination>().ConvertUsing(new ConvertSourceToDestination());
});
return config;
}
}
You can add a method on Source class to fetch the child list. 您可以在Source类上添加一个方法来获取子级列表。 Then it's very easy to map . 然后,很容易映射。
Instead of using a custom type converter, it may be better to use a custom value resolver and leave the rest of the mapping to AutoMapper. 与其使用自定义类型转换器,不如使用自定义值解析器 ,并将其余映射留给AutoMapper可能更好。 In this case, it's not difficult to map source.Name
to destination.Name
, but imagine you had 10 other properties that AutoMapper could handle, or that you could use the default opt.MapFrom
for. 在这种情况下,将source.Name
映射到destination.Name
并不困难,但是假设您有AutoMapper可以处理的其他10个属性,或者可以使用默认的opt.MapFrom
。
Example custom value resolver: 自定义值解析器示例:
public class SourceToDestinationChildResolver : IValueResolver<Source, Destination, List<Child>>
{
public List<Child> Resolve(Source source, Destination destination, List<Child> member, ResolutionContext context)
{
destination = destination ?? new Destination();
destination.Children = destination.Children ?? new List<Child>();
destination.Children.Add(new Child() { Property1 = source.Child1Property1, Property2 = source.Child1Property2 });
destination.Children.Add(new Child() { Property1 = source.Child2Property1, Property2 = source.Child2Property2 });
// This is not needed then
// destination.Name = source.Name;
return destination.Children;
}
}
Configuration to use resolver: 使用解析器的配置:
public static class AutoMapperConfiguration
{
public static MapperConfiguration Configure()
{
var config = new MapperConfiguration(
cfg =>
{
cfg.CreateMap<Source, Destination>()
.ForMember(dest => dest.Children, opt => opt.MapFrom<SourceToDestinationChildResolver>())
});
return config;
}
}
One thing that could help clarify my solution for myself is how is List<Child> member
exactly used. 可以帮助澄清我自己的解决方案的一件事是,如何正确使用List<Child> member
。 Was not clear for me in the documentation, so someone please comment :) 在文档中对我来说不清楚,所以请有人发表评论:)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.