繁体   English   中英

AutoMapper 按条件将一个属性映射到两个属性

[英]AutoMapper Mapping one property to two properties by condition

有两个班

        class A
        {
            public string ProductionDivision { get; set; }
        }


        class B
        {
            private object _productionDivision;

            public enum ProductionDivisionOneofCase
            {
                None = 0,
                IsNullproductionDivision = 15,
                ProductionDivisionValue = 16,
            }
            private ProductionDivisionOneofCase _productionDivisionCase = ProductionDivisionOneofCase.None;


            public bool IsNullProductionDivision
            {
                get { return _productionDivisionCase == ProductionDivisionOneofCase.IsNullproductionDivision ? (bool)_productionDivision : false; }
                set
                {
                    _productionDivision = value;
                    _productionDivisionCase = ProductionDivisionOneofCase.IsNullproductionDivision;
                }
            }

            public string ProductionDivisionValue
            {
                get { return _productionDivisionCase == ProductionDivisionOneofCase.ProductionDivisionValue ? (string)_productionDivision : ""; }
                set
                {
                    _productionDivision = value;
                    _productionDivisionCase = ProductionDivisionOneofCase.ProductionDivisionValue;
                }
            }
        }

I would like to map the ProductionDivision property to one of properties of class B depending on the condition - null (map to IsNullProductionDivision ) or not null (map to ProductionDivisionValue ) of the source property value. 我可以像下面这样实现它。

CreateMap<A, B>()
               .ForMember(g => g.IsNullProductionDivision, m =>
               {
                   m.PreCondition(s => s.ProductionDivision == null);
                   m.MapFrom(b => true);
               })
               .ForMember(g => g.ProductionDivisionValue, m =>
               {
                   m.PreCondition(s => s.ProductionDivision != null);
                   m.MapFrom(b => b.ProductionDivision);
               });

如果 {source property name} 的值为null那么 IsNull{source property name} 的值为true 否则,如果 {source property name} 的值不是null则 {source property name}Value 的值是 {source property name} 的值。

我有许多响应此映射规则的属性。 所以,我不想为上面的每个属性编写映射规则。 我想为这样的映射全局配置一个规则。

如何配置 AutoMapper 以便它可以处理如此复杂的映射?

我找到了解决方案。 解决方案非常简单明了。 结果如下:

完整代码:

public class Program
{

    class A
    {
        public string ProductionDivision { get; set; }
    }


    class B
    {
        private object _productionDivision;

        public enum ProductionDivisionOneofCase
        {
            None = 0,
            IsNullproductionDivision = 15,
            ProductionDivisionValue = 16,
        }
        private ProductionDivisionOneofCase _productionDivisionCase = ProductionDivisionOneofCase.None;


        public bool IsNullProductionDivision
        {
            get { return _productionDivisionCase == ProductionDivisionOneofCase.IsNullproductionDivision ? (bool)_productionDivision : false; }
            set
            {
                _productionDivision = value;
                _productionDivisionCase = ProductionDivisionOneofCase.IsNullproductionDivision;
            }
        }

        public string ProductionDivisionValue
        {
            get { return _productionDivisionCase == ProductionDivisionOneofCase.ProductionDivisionValue ? (string)_productionDivision : ""; }
            set
            {
                _productionDivision = value;
                _productionDivisionCase = ProductionDivisionOneofCase.ProductionDivisionValue;
            }
        }
    }

   public class StrinToBoolCustomResolver
        : IValueConverter<string, bool>
    {
        public bool Convert(string sourceMember, ResolutionContext context)
        {
            return sourceMember == null;
        }
    }

    public class MyAutoMapperProfile
        : Profile
    {
        public MyAutoMapperProfile()
        {
            // add post and pre prefixes to add corresponding properties in the inner property map
            RecognizeDestinationPostfixes("Value");
            RecognizeDestinationPrefixes("IsNull");

            // add mapping for "value" property
            this.ForAllPropertyMaps(map => map.SourceMember.Name + "Value" == map.DestinationName,
                (map, expression) =>
                {
                    expression.Condition((source, dest, sMem, destMem) =>
                    {
                        return sMem != null;
                    });
                    expression.MapFrom(map.SourceMember.Name);
                });

            // add mapping for "IsNull" property
            this.ForAllPropertyMaps(map => "IsNull" + map.SourceMember.Name == map.DestinationName,
                (map, expression) =>
                {
                    expression.Condition((source, dest, sMem, destMem) =>
                    {
                        return (bool)sMem;
                    });
                    //expression.MapFrom(map.SourceMember.Name);
                    expression.ConvertUsing<string, bool>(new StrinToBoolCustomResolver(), map.SourceMember.Name);
                });



            CreateMap<A, B>();
               //.ForMember(g => g.IsNullProductionDivision, m =>
               //{
               //    m.PreCondition(s => s.ProductionDivision == null);
               //    m.MapFrom(b => true);
               //});
               //.ForMember(g => g.ProductionDivisionValue, m =>
               //{
               //    m.PreCondition(s => s.ProductionDivision != null);
               //    m.MapFrom(b => b.ProductionDivision);
               //});
        }
    }


    public static void Main(string[] args)
    {
        var configuration = new MapperConfiguration(cfg => {
            cfg.AddProfile(new MyAutoMapperProfile());
        });

        var mapper = new Mapper(configuration);
        mapper.ConfigurationProvider.AssertConfigurationIsValid();
        var a = new A()
        {
            ProductionDivision = null
        };
        // b._productionDivisionCase  will be equal IsNullproductionDivision 
        var b = mapper.Map<B>(a);

        var c = new A()
        {
            ProductionDivision = "dsd"
        };
        // d._productionDivisionCase  will be equal ProductionDivisionValue
        var d = mapper.Map<B>(c);
    }
}

澄清:

  1. 添加(后/前)修复以将相应的属性添加到内部属性 map。 它需要在这里做,因为我们的属性应该被 AutoMapper 捕获。 否则属性将被放弃并且映射器配置将失败。

  2. 之后,我们配置这些属性需要如何映射。 我们调用ForAllPropertyMaps方法,过滤所有属性并设置规则以映射适合我们过滤器的属性。 在创建映射器 object 时,将构建执行计划并查看指定的过滤器。

  • 对于“值”属性,我们添加一个条件来检查源属性是否不是 null。 如果是 null,则映射会丢失。
  • 对于“IsNull”属性首先,我们添加一个转换器,将字符串类型转换为布尔类型。 转换器只是将源字符串属性与 null 值进行比较。 如果源属性等于 null,则转换器返回 true。 因此,条件接收到一个真值,返回真,并且映射将完成。 否则转换器返回 false,因此条件返回 false,映射将丢失。

因此,根据源属性是否为 null 值,源属性将映射到不同的目标属性。 除此之外,如果不是必须调用的,则不会调用相应目标属性的相应 set 方法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM