AutoMapper和压扁嵌套数组(AutoMapper and flattening nested

2019-07-03 18:01发布

我试图使用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的目的地命名约定来处理阵列(或其他枚举)。

对任何见解如何实现这一目标?

Answer 1:

试试这个映射器,

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);


Answer 2:

我前一阵子有一个非常类似的问题。 我的位置集合,每个位置有街道的集合。 我想将它们映射到视图模型的集合,其中每个视图模型所代表的街道(包括位置信息)。

这是我的解决方案: 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"));
    }
}


文章来源: AutoMapper and flattening nested arrays