确定要映射到基于ob属性值的类型

时间:2018-01-15 13:00:15

标签: c# automapper

通常,您将Automapper配置为从类型A映射到类型B.我需要使用automapper映射到类型B或类型C,具体取决于类型A中的属性值。我还需要从类型B或类型映射回来C键入A。

到目前为止提出的解决方案是定义两种类型映射(A => B,A => C)并根据鉴别器调用自定义if / switch contruct中的正确映射。映射嵌套类型,此解决方案不起作用,因为将调用优越的映射。

例如,根据动物的AnimalType值,类型Animal被映射到猫或狗。

我还需要从猫或狗的方式回来,这应该很简单,因为在这里我可以定义2个固定的关系(dog => animal,cat => animal)。

可以映射animal =>要么定义狗还是猫?如果是这样,怎么样?

    public enum EAnimalType
    {
        Cat = 1,
        Dog = 2
    }

    public class Animal
    {
        public EAnimalType AnimalType { get; set; }

        public int Age { get; set; }
    }

    public abstract class AnimalDto
    {
        public int Age { get; set; }
    }

    public class CatDto : AnimalDto {}

    public class DogDto : AnimalDto {}

2 个答案:

答案 0 :(得分:1)

定义基本类型的映射。此映射使用ConstructUsing通过调用适用的子映射来实例化正确的子DTO。使用AutoMapper 3.0进行测试。

CreateMap<Animal, AnimalDto>()
      // create DTO by dispatching to child type mappings
      .ConstructUsing((animal, context) => {
           switch (animal.AnimalType) {
               case EAnimalType.Dog:
                   return context.Mapper.Map<DogDto>(animal);
               case EAnimalType.Cat:
                   return context.Mapper.Map<CatDto>(animal);
               default:
                   throw new NotSupportedException(
                       $"Animal Type '{animal.AnimalType}' is not supported."
                   );
           }       
       })
      // map members of base type
      .ForMember(dto => dto.Age, o => o.MapFrom(ent => ent.Age));

      // mappings for child types, will handle dispatch from base type
      CreateMap<Animal, DogDto>()
           .ForMember(dto => dto.Age, o => o.Ignore()) // already mapped from base type 
           .ForMember(dto => dto.DogSpecific, o => o.MapFrom(dog => dog.DogSpecific));

      CreateMap<Animal, CatDto>()
           .ForMember(dto => dto.Age, o => o.Ignore()); // already mapped from base type

要实现此功能,Animal, DogDto配置中使用的AutoMapper必须可以访问映射Animal, CatDtoAnimal, AnimalDto(例如,在同一个AutoMapper配置文件中定义)。

答案 1 :(得分:0)

使用类型转换器,可以从a映射到b或c。这是有效的,因为在类型转换器中我自己定义了映射指令。缺点:手动定义映射,必须更新,例如,将属性添加到类中。

也许存在更好的解决方案?

    [TestMethod]
    public void VerifyMappingsSecuritiesModule()
    {
        // Arrange
        Mapper.Initialize(cfg =>
            {
                cfg.CreateMap<Animal, AnimalDto>().ConvertUsing<TypeTypeConverter>();
            });

        var expectedAge = 10;
        var animal = new Animal { Age = expectedAge, AnimalType = EAnimalType.Cat };

        // Act
        var catDto = Mapper.Map<Animal, AnimalDto>(animal);

        // Assert
        Assert.IsInstanceOfType(catDto, typeof(CatDto));
        Assert.AreEqual(expectedAge, catDto.Age);
    }

    public class TypeTypeConverter : ITypeConverter<Animal, AnimalDto>
    {
        public AnimalDto Convert(ResolutionContext context)
        {
            var animal = (Animal)context.SourceValue;

            if (animal.AnimalType == EAnimalType.Cat) { return new CatDto { Age = animal.Age }; }
            else { return new DogDto { Age = animal.Age };  }
        }
    }