【问题标题】:AutoMapper and flattening nested arraysAutoMapper 和展平嵌套数组
【发布时间】:2012-10-31 13:19:04
【问题描述】:

我正在尝试使用 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 的目标命名约定。

关于如何实现这一点的任何见解?

【问题讨论】:

    标签: c# flatten automapper-2


    【解决方案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);
    

    【讨论】:

    • 如果 B 或 D 为 null 或零长度数组,则会抛出 AutoMapperMappingException。 X[] arrayOfX = new X[] {new X() {A = "a1", B = null}, new X() {A = "a2", B = new Y[] {}}};跨度>
    • @JayWalker 编辑了我的帖子。刚刚添加了空检查。感谢您的发现。
    【解决方案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"));
        }
    }
    

    【讨论】:

      【解决方案3】:

      对于通过搜索如何使用 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);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-04-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-05-28
        • 2015-03-14
        • 2017-03-06
        • 2017-07-20
        相关资源
        最近更新 更多