【问题标题】:Is there a way to properly use AutoMapper to implements inheritance with discriminator?有没有办法正确使用 AutoMapper 来实现带判别器的继承?
【发布时间】:2019-02-04 07:41:50
【问题描述】:

我的业务逻辑 Pet 类中有一个 Model 类。

在这个类中,我有一个称为 Type (int = 1, 2, 3, ...) 的鉴别器属性

最终的映射必须是特定派生类的Dto。

我使用了 ConstructUsing,但由于它对基类型映射规则有递归,所以它会引发 Stack Overflow 异常。

派生的 Dto 类被正确映射,因为它们没有递归。

也试过 PreserveReferences() 没有运气

using AutoMapper;
using System;
using System.Collections.Generic;

namespace ConsoleAppMapper
{
    class Program
    {
        static void Main(string[] args)
        {
            var mapper = new MapperConfiguration(cfg =>
            {
                cfg.CreateMap<Pet, Dto.Pet>()
                    .PreserveReferences()
                    .ForMember(dst => dst.Name, opt => opt.MapFrom(src => src.PetName))
                    .ConstructUsing((src, context) =>
                    {
                        switch (src.Type)
                        {
                            case 1: return context.Mapper.Map<Pet, Dto.Dog>(src);
                            case 2: return context.Mapper.Map<Pet, Dto.Cat>(src);
                            case 3: return context.Mapper.Map<Pet, Dto.Mouse>(src);
                            default: return context.Mapper.Map<Pet, Dto.Pet>(src);
                        }
                    })
                ;
                cfg.CreateMap<Pet, Dto.Dog>();
                cfg.CreateMap<Pet, Dto.Cat>();
                cfg.CreateMap<Pet, Dto.Mouse>();
            }).CreateMapper();

            var pets = new List<Pet>
            {
                new Pet { PetName = "Bob", Type = 1 },
                new Pet { PetName = "Tom", Type = 2 },
                new Pet { PetName = "Jerry", Type = 3 },
                new Pet { PetName = "Duffy", Type = 4 },
            };
            var dtoList = mapper.Map<IEnumerable<Pet>, IEnumerable<Dto.Pet>>(pets);
        }
    }

    public class Pet
    {
        public string PetName;
        public int Type;
    }
}

namespace Dto
{
    public class Pet
    {
        public string Name;
    }

    public class Dog : Pet
    {
    }

    public class Cat : Pet
    {
    }

    public class Mouse : Pet
    {
    }
}

更新: 有了这个版本,它似乎可以正常工作

cfg.CreateMap<Pet, Dto.Pet>()
    .ForMember(dst => dst.Name, opt => opt.MapFrom(src => src.PetName))
    .ConstructUsing((src, context) =>
    {
        switch (src.Type)
        {
            case 1: return context.Mapper.Map<Pet, Dto.Dog>(src);
            case 2: return context.Mapper.Map<Pet, Dto.Cat>(src);
            case 3: return context.Mapper.Map<Pet, Dto.Mouse>(src);

            default: return context.Mapper.Map(src, new Dto.Pet { }, context);
        }
    })
;
cfg.CreateMap<Pet, Dto.Dog>();
cfg.CreateMap<Pet, Dto.Cat>();
cfg.CreateMap<Pet, Dto.Mouse>();

【问题讨论】:

  • 似乎 Map 方法重载可以解决问题,但我不确定这是做我想做的事情的正确方法。 default: return context.Mapper.Map(src, new Dto.Pet { }, context);
  • 是的,您必须手动传递上下文。这已用github.com/AutoMapper/AutoMapper/issues/2937 更改,因此不再需要。尝试MyGet 构建。
  • 最新的 myGet 版本将如何解决此问题?我已经尝试了最后一次 MyGet 构建,但这不是重点。它不起作用的是default: return context.Mapper.Map&lt;Pet, Dto.Pet&gt;(src);。它的工作原理是default: return context.Mapper.Map&lt;Pet, Dto.Pet&gt;(src, new Dto.Pet { });
  • 可能只是参考问题?
  • 正如我已经说过的,改变的是你不必再显式地传递上下文了。您需要有相同的上下文以避免 SO。

标签: c# inheritance automapper discriminator


【解决方案1】:

这是我的完整解决方案,它涵盖了所有映射组合

using AutoMapper;
using System;
using System.Collections.Generic;

namespace ConsoleAppMapper
{
    class Program
    {
        static void Main(string[] args)
        {
            var mapper = new MapperConfiguration(cfg =>
            {
                cfg.CreateMap<Pet, Dto.Pet>()
                    .Include<Pet, Dto.Dog>()
                    .Include<Pet, Dto.Cat>()
                    .Include<Pet, Dto.Mouse>()

                    .ForMember(dst => dst.Name, opt => opt.MapFrom(src => src.PetName))
                    .ForMember(dst => dst.Description, opt => opt.Ignore())

                    .ConstructUsing((src, context) =>
                    {
                        switch (src.Type)
                        {
                            case 1: return context.Mapper.Map(src, new Dto.Dog { }, context);
                            case 2: return context.Mapper.Map(src, new Dto.Cat { }, context);
                            case 3: return context.Mapper.Map(src, new Dto.Mouse { }, context);
                            default: return context.Mapper.Map(src, new Dto.Pet { }, context);
                        }
                    })
                ;

                cfg.CreateMap<Pet, Dto.Dog>()
                    .ForMember(dst => dst.Description, opt => opt.MapFrom(src => "This is a dog"))
                ;

                cfg.CreateMap<Pet, Dto.Cat>()
                    .ForMember(dst => dst.Description, opt => opt.MapFrom(src => "This is a cat"))
                ;

                cfg.CreateMap<Pet, Dto.Mouse>()
                    .ForMember(dst => dst.Description, opt => opt.MapFrom(src => "This is a mouse"))
                ;

            }).CreateMapper();

            // Test
            var pets = new List<Pet>
            {
                new Pet { PetName = "Bob", Type = 1 },
                new Pet { PetName = "Tom", Type = 2 },
                new Pet { PetName = "Jerry", Type = 3 },
                new Pet { PetName = "Duffy", Type = 4 },
            };

            // Full mixed collection
            var dtoList = mapper.Map<IEnumerable<Pet>, IEnumerable<Dto.Pet>>(pets);

            // Single item
            var dog = mapper.Map<Pet, Dto.Pet>(pets[0]); 
            var dog2 = mapper.Map<Pet, Dto.Dog>(pets[0]); 
        }
    }

    public class Pet
    {
        public string PetName;
        public int Type;
    }
}

namespace Dto
{
    public class Pet
    {
        public string Name;
        public string Description;
    }

    public class Dog : Pet
    {
    }

    public class Cat : Pet
    {
    }

    public class Mouse : Pet
    {
    }
}

【讨论】:

  • 感谢 Lucian Bargaoanu 的支持。我等待 8.1 版本放弃传递上下文作为参数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-02-04
  • 2011-12-06
  • 1970-01-01
  • 1970-01-01
  • 2019-09-30
  • 2019-05-09
  • 2013-11-17
相关资源
最近更新 更多