有没有办法正确使用AutoMapper来实现鉴别器的继承?
Is there a way to properly use AutoMapper to implements inheritance with discriminator?
我的业务逻辑中只有一个模型 class,宠物 class。
在这个 class 中,我有一个鉴别器 属性 称为 Type (int = 1, 2, 3, ...)
最终映射必须是特定派生的classes的Dto。
我使用了 ConstructUsing,但它继续出现 Stack Overflow Exception,因为它对基本类型映射规则有递归。
派生的 Dto classes 已正确映射,因为它们没有递归。
也试过 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>();
这是我的完整解决方案,它涵盖了所有映射组合
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
{
}
}
我的业务逻辑中只有一个模型 class,宠物 class。
在这个 class 中,我有一个鉴别器 属性 称为 Type (int = 1, 2, 3, ...)
最终映射必须是特定派生的classes的Dto。
我使用了 ConstructUsing,但它继续出现 Stack Overflow Exception,因为它对基本类型映射规则有递归。
派生的 Dto classes 已正确映射,因为它们没有递归。
也试过 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>();
这是我的完整解决方案,它涵盖了所有映射组合
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
{
}
}