c# - AutoMapper - 不使用映射配置文件的相同类型的映射集合
问题描述
我在将相同类型对象的集合映射到AutoMapper
. 让我给你举个例子 :
一、对象类:
public class ClassA
{
public string Name { get; set; }
public string Type { get; set; }
}
public class ClassB
{
public string Name { get; set; }
public List<ClassA> Classes { get; set; }
}
public class MappingProfile : Profile
{
public MappingProfile()
{
CreateMap<ClassA, ClassA>()
.ForMember(dest => dest.Name, opts => opts.MapFrom(src => src.Name))
.ForAllOtherMembers(opts => opts.Ignore());
CreateMap<ClassB, ClassB>()
.ForMember(dest => dest.Name, opts => opts.MapFrom(src => src.Name))
.ForMember(dest => dest.Classes, opts => opts.MapFrom(src => src.Classes))
.ForAllOtherMembers(opts => opts.Ignore());
}
}
现在在执行这样的代码时:
List<ClassB> targetList;
targetList = DbContext.ClassesB.ProjectTo<ClassB>(Mapper.ConfigurationProvider).ToList();
映射无法正常工作。ClassB.Name
被正确映射,但看起来映射定义ClassA
被忽略了,因为所有属性都被映射了。此外,当我将ClassB.Classes
属性更改为 no-list ( ClassA
) 时,映射工作正常。
忽略定义的映射是错误的吗AutoMapper
?
解决方案
如果您查看从 生成的表达式ProjectTo<ClassB>
,您可以看到映射实际上是如何进行的。
var expression = DbContext.ClassesB.ProjectTo<ClassB>(Mapper.ConfigurationProvider).Expression;
Console.WriteLine(expression);
结果:
[Microsoft.EntityFrameworkCore.Query.QueryRootExpression]
.Select(dtoClassB => new ClassB() {Classes = dtoClassB.Classes, Name = dtoClassB.Name})
在这里,List<ClassA>
不是逐项映射,而是简单地分配给目标对象。我不知道这是故意设计的还是一个错误。
使用静态 API,您可以使用以下配置解决问题:
CreateMap<ClassA, ClassA>()
.ForMember(dest => dest.Name, opts => opts.MapFrom(src => src.Name))
.ForAllOtherMembers(opts => opts.Ignore());
CreateMap<ClassB, ClassB>()
.ForMember(dest => dest.Name, opts => opts.MapFrom(src => src.Name))
.ForMember(dest => dest.Classes, opts => opts.MapFrom(src => src.Classes.Select(a => Mapper.Map<ClassA>(a)).ToList()))
.ForAllOtherMembers(opts => opts.Ignore());
Instance API 的变通方法不是很实用也很麻烦,但我还是把它带到这里。您必须创建 2 个配置文件,其中一个仅用于映射ClassA
public class MappingClassAProfile : Profile
{
public MappingClassAProfile()
{
CreateMap<ClassA, ClassA>()
.ForMember(dest => dest.Name, opts => opts.MapFrom(src => src.Name))
.ForAllOtherMembers(opts => opts.Ignore());
}
}
public class MappingProfile : MappingClassAProfile
{
public MappingProfile(IMapper mapper) : base()
{
CreateMap<ClassB, ClassB>()
.ForMember(dest => dest.Name, opts => opts.MapFrom(src => src.Name))
.ForMember(dest => dest.Classes, opts => opts.MapFrom(src => src.Classes.Select(a => mapper.Map<ClassA>(a)).ToList()))
.ForAllOtherMembers(opts => opts.Ignore());
}
}
然后按如下方式构建映射器:
var configurationBase = new MapperConfiguration(cfg =>
{
cfg.AddProfile<MappingClassAProfile>();
});
var mapperA = configurationBase.CreateMapper();
var configuration = new MapperConfiguration(cfg =>
{
cfg.AddProfile(new MappingProfile(mapperA));
});
var mapper = configuration.CreateMapper(); // use it to project ClassB instances
推荐阅读
- sql - PL/SQL Developer 命令窗口脚本编码
- c# - 单击图表并使用 MVVM 在另一个窗口中打开相同的图表?
- vim - 在多行上从行尾更改第 n 列
- google-cloud-platform - 将云存储和云运行映射到同一域以避免CORS
- spring-boot - 当 Hashicorp 保险库被密封时,令牌身份验证不起作用
- c# - MVC Dropdownlist 只返回项目的 id,而不是项目的名称
- javascript - Electron:从 main.js 向 index.js 发送消息
- spring-boot - 如何在 Spring Boot 中验证唯一的事务 ID?
- javascript - 如何在 NodeJS 中以正确的顺序传递消息?
- python - Plotly Choropleth Map Plots 的下拉菜单