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

时间:2019-11-04 16:07:04

标签: c# automapper

有两个班级

/* ... start of your file */
class Foo {};
typedef FooMap<Foo,5>::Iterator FooIterator;
int main()
{
}

我想根据条件- 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; } } } (映射到ProductionDivision)还是不null(映射,将IsNullProductionDivision属性映射到B类的一个属性到源属性值的null)。我可以做到如下。

ProductionDivisionValue

如果{源属性名称}的值为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); }); ,则IsNull {源属性名称}的值为null。 否则,如果{源属性名称}的值不是true,则{源属性名称} Value的值就是{源属性名称}的值。

我有许多属性可以响应此映射规则。因此,我不想为上述每个属性编写映射规则。我想在全球范围内配置此类映射的规则。

如何配置AutoMapper,使其能够处理这种复杂的映射?

1 个答案:

答案 0 :(得分:1)

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

完整代码:

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. 添加(post/pre)fixes,以将相应的属性添加到内部属性映射中。它需要在这里做,因为我们的属性应该被AutoMapper捕获。否则,属性将被放弃,并且映射器配置将失败。

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

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

因此,取决于源属性是否为空值,源属性的映射将发生到不同的目标属性。除此之外,如果不需要调用相应目标属性的相应set方法,则不会调用它。