【问题标题】:AutoMapper - Mapping collection of the same types not using mapping profileAutoMapper - 不使用映射配置文件的相同类型的映射集合
【发布时间】:2021-02-25 11:00:40
【问题描述】:

我在使用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 的错误是它忽略了定义的映射吗?

【问题讨论】:

标签: c# .net-core automapper


【解决方案1】:

如果您查看从 ProjectTo&lt;ClassB&gt; 生成的表达式,您可以看到映射的实际情况。

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&lt;ClassA&gt; 不是逐项映射的,而是简单地分配给目标对象。我不知道这是故意设计的还是一个错误。

使用静态 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

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-11-15
  • 2019-03-01
  • 2017-04-16
  • 2015-09-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多