我正在尝试使用AutoMapper来压缩多个级别的数组。
考虑以下源类:
class X {
public string A { get; set; }
public Y[] B { get; set; }
}
class Y {
public string C { get; set; }
public Z[] D { get; set; }
}
class Z {
public string E { get; set; }
public string F { get; set; }
}
以下目的地:
class Destination {
public string A { get; set; }
public string C { get; set; }
public string E { get; set; }
public string F { get; set; }
}
我希望能够从一个或多个X中获取一个列表,例如:
Mapper.Map<IEnumerable<X>, IEnumerable<Destination>>(arrayOfX);
我无法弄清楚要使用哪种映射配置来实现这一目标。 MapFrom似乎是1:1合成的方式,但似乎无法处理数组(或其他可枚举),除非我使用AutoMapper的目标命名约定。
有关如何实现这一目标的任何见解?
答案 0 :(得分:9)
试试这个映射器,
Mapper.CreateMap<Z, Destination>();
Mapper.CreateMap<Y, Destination>();
Mapper.CreateMap<X, Destination>()
.ForMember(destination => destination.A, options => options.MapFrom(source => source.A)).IgnoreAllNonExisting()
.ForMember(destination => destination.C, options => options.MapFrom(source => Mapper.Map<IEnumerable<Y>, IEnumerable<Destination>>(source.B).FirstOrDefault().C))
.ForMember(destination => destination.E, options => options.MapFrom(source => Mapper.Map<IEnumerable<Z>, IEnumerable<Destination>>(source.B.SelectMany(d => d.D)).FirstOrDefault().E))
.ForMember(destination => destination.F, options => options.MapFrom(source => Mapper.Map<IEnumerable<Z>, IEnumerable<Destination>>(source.B.SelectMany(d => d.D)).FirstOrDefault().F));
var result = Mapper.Map<IEnumerable<X>, IEnumerable<Destination>>(arrayOfX);
答案 1 :(得分:4)
前一段时间我遇到了类似的问题。我收集了一些地点,每个地点都有一系列街道。我想将它们映射到一组视图模型,其中每个视图模型代表一条街道(包括位置详细信息)。
这是我的解决方案:https://groups.google.com/forum/#!topic/automapper-users/b66c1M8eS8E
对于这个特殊问题,这可能是您的映射配置:
public static class AutoMapperConfig
{
public static void Configure()
{
Mapper.CreateMap<Z, Destination>()
.ForMember(dest => dest.A, opt => opt.Ignore())
.ForMember(dest => dest.C, opt => opt.Ignore());
Mapper.CreateMap<Y, Destination>()
.ForMember(dest => dest.A, opt => opt.Ignore())
.ForMember(dest => dest.E, opt => opt.Ignore())
.ForMember(dest => dest.F, opt => opt.Ignore());
Mapper.CreateMap<X, Destination>()
.ForMember(dest => dest.C, opt => opt.Ignore())
.ForMember(dest => dest.E, opt => opt.Ignore())
.ForMember(dest => dest.F, opt => opt.Ignore());
}
}
因为AutoMapper主要是1:1映射,所以你需要实现一点魔法来映射到多个对象。这是一个如何调用该映射来填充对象的示例:
var rc = data.SelectMany(
x => x.B.SelectMany(
y => y.D
.Select(Mapper.Map<Z, Destination>)
.Select(z => Mapper.Map(y, z))
)
.Select(y => Mapper.Map(x, y))
);
以下是一些单元测试,用于验证映射并将其显示在行动中:
[TestFixture]
public class MapperTests
{
[Test]
public void Mapping_Configuration_IsValid()
{
AutoMapperConfig.Configure();
Mapper.AssertConfigurationIsValid();
}
[Test]
public void Mapping_TestItems_MappedOK()
{
AutoMapperConfig.Configure();
Mapper.AssertConfigurationIsValid();
var data = new[]
{
new X
{
A = "A1",
B = new[]
{
new Y
{
C = "A1C1",
D = new[]
{
new Z
{
E = "A1C1E1",
F = "A1C1F1"
},
new Z
{
E = "A1C1E2",
F = "A1C1F2"
},
}
},
new Y
{
C = "A1C2",
D = new[]
{
new Z
{
E = "A1C2E1",
F = "A1C2F1"
},
new Z
{
E = "A1C2E2",
F = "A1C2F2"
},
}
}
}
}
};
var rc = data.SelectMany(
x => x.B.SelectMany(
y => y.D
.Select(Mapper.Map<Z, Destination>)
.Select(z => Mapper.Map(y, z))
)
.Select(y => Mapper.Map(x, y))
);
Assert.That(rc, Is.Not.Null);
Assert.That(rc.Count(), Is.EqualTo(4));
var item = rc.FirstOrDefault(x => x.F == "A1C2F2");
Assert.That(item, Is.Not.Null);
Assert.That(item.A, Is.EqualTo("A1"));
Assert.That(item.C, Is.EqualTo("A1C2"));
Assert.That(item.E, Is.EqualTo("A1C2E2"));
Assert.That(item.F, Is.EqualTo("A1C2F2"));
}
}
答案 2 :(得分:0)
对于通过搜索如何使用AutoMapper展平对象结构来解决本文的其他人-新的AutoMapper支持使用IncludeMembers()语法展平。
来源:http://docs.automapper.org/en/stable/Flattening.html
因此可以像这样解决原始问题:
Mapper.CreateMap<Z, Destination>();
Mapper.CreateMap<Y, Destination>().IncludeMembers(src => src.D);
Mapper.CreateMap<X, Destination>().IncludeMembers(src => src.B);