AutoMapper and flattening nested arrays

前端 未结 3 1140
傲寒
傲寒 2020-12-09 00:31

I\'m trying to use AutoMapper to flatten multiple levels of arrays.

Consider the following source classes:

class X {
    public string A { get; set;         


        
相关标签:
3条回答
  • 2020-12-09 00:51

    I had a very similar problem a while ago. I had a collection of locations, and each location had a collection of streets. I wanted to map them to a collection of view models where each view model represented a street (including the location details).

    This was my solution: https://groups.google.com/forum/#!topic/automapper-users/b66c1M8eS8E

    For this particular problem, this could be your mapping configuration:

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

    Because AutoMapper is primarily a 1:1 mapping, you need to implement a wee bit of magic to map to multiple objects. This is an example of how you could call that mapping to populate your object:

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

    Here are a couple of unit tests to validate the mapping and show it in action:

    [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"));
        }
    }
    
    0 讨论(0)
  • 2020-12-09 01:06

    Try this mapper,

    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);
    
    0 讨论(0)
  • 2020-12-09 01:07

    For anyone else coming across this post by searching how to Flatten object structure with AutoMapper - the new AutoMapper supports flattening with IncludeMembers() syntax.

    Source: http://docs.automapper.org/en/stable/Flattening.html

    So the original issue could be solved like this:

    Mapper.CreateMap<Z, Destination>();
    Mapper.CreateMap<Y, Destination>().IncludeMembers(src => src.D);
    Mapper.CreateMap<X, Destination>().IncludeMembers(src => src.B);
    
    0 讨论(0)
提交回复
热议问题