代码之家  ›  专栏  ›  技术社区  ›  Brandon

自动映射->条件映射

  •  1
  • Brandon  · 技术社区  · 6 年前

    我正在尝试做一些条件映射,我读过的所有文档和问题似乎都没有涵盖这个特定的条件。我希望这里的人能有经验或者知道如何最好地解决这个问题。

    我正在映射一个具有两个属性的对象。但是,如果某个特定属性具有值,则我不想映射任何一个属性。要将其可视化:

    foreach(var object in objectB) {
        If (object.propertyA == "SomeValue")
            continue;
        else
            Mapper.Map<ObjectA>(object);
    }
    

    但是,我想要 AutoMapper 等同于上述声明。所以更像是:

    cfg.CreateMap<ObjectB, ObjectA>()
        .ForMember(dest => dest.PropertyA, m => m.Condition(source => source.PropertyA != "SomeValue"))
        .ForMember(dest => dest.PropertyB, m => m.Condition(source => source.PropertyA != "SomeVAlue" ? source.PropertyB : ignore))
    

    但上述版本显然行不通。 提前感谢您的帮助。

    1 回复  |  直到 6 年前
        1
  •  3
  •   Sergey Prosin    6 年前

    可以使用条件映射实现,请参见文档( http://docs.automapper.org/en/latest/Conditional-mapping.html )详细情况。为了涵盖数组过滤的情况,我创建了一个自定义类型转换器,这有点棘手(请参见 http://docs.automapper.org/en/stable/Custom-type-converters.html ). 更新的示例如下

    using AutoMapper;
    using System;
    using System.Collections.Generic;
    
    namespace ConsoleAppTest2
    {
        class Program
        {
            static void Main(string[] args)
            {
    
                Mapper.Initialize(cfg => {
                    //Using specific type converter for specific arrays
                    cfg.CreateMap<Foo[], FooDto[]>().ConvertUsing(new ArrayFilterTypeConverter<Foo[], FooDto[], Foo, FooDto>(
                                                                                                                   (src, dest) => (src.Age > 0)
                                                                                                                ));
    
                    cfg.CreateMap<Foo, FooDto>()
                        .ForMember(dest => dest.Age, opt => opt.Condition(src => (src.Age >= 0)))
                        .ForMember(dest => dest.CurrentAddress, opt =>
                                                                    {
                                                                        opt.Condition(src => (src.Age >= 0));
                                                                        opt.MapFrom(src => src.Address);
                                                                    });
    
                });
    
                var foo = new Foo() { Name = "Name", Address = "Address", Age = -1 };
                var fooDTO = new FooDto();
    
    
                var fooArray = new Foo[] {
                        new Foo() { Name = "Name1", Address = "Address1", Age = -1 },
                        new Foo() { Name = "Name2", Address = "Address2", Age = 1 },
                        new Foo() { Name = "Name3", Address = "Address3", Age = 1 }
                };
    
                var fooDTOArray =  Mapper.Map<Foo[], FooDto[]>(fooArray); //get 2 elements instead of 3
    
                Mapper.Map(foo, fooDTO);
                //The result is we skipped Address and Age properties becase Age is negative
    
                Console.ReadLine();
            }
        }
    
        public class ArrayFilterTypeConverter<TSourceArray, TDestArray, TSource, TDest> : ITypeConverter<TSourceArray, TDestArray>
        {
            private Func<TSource, TDest, bool> filter;
    
            public ArrayFilterTypeConverter(Func<TSource, TDest, bool> filter)
            {
                this.filter = filter;
            }
    
            public TDestArray Convert(TSourceArray source, TDestArray destination, ResolutionContext context)
            {
                var sourceArray = source as TSource[];
                List<TDest> destList = new List<TDest>();
    
                var typeMap = context.ConfigurationProvider.ResolveTypeMap(typeof(TSource), typeof(TDest));
    
                foreach (var src in sourceArray)
                {
                    var dest = context.Mapper.Map<TSource, TDest>(src);
    
                    if (filter(src, dest))
                        destList.Add(dest);
                }
    
                // Little hack to cast array to TDestArray
                var result = (TDestArray)(object)destList.ToArray();
                return result;
            }
        }
    
        internal class FooDto
        {
            public string Name { get; set; }
            public string CurrentAddress { get; set; }
            public int Age { get; set; }
    
        }
    
        internal class Foo
        {
            public string Name { get; set; }
            public string Address { get; set; }
    
            public int Age { get; set; }
        }
    }