自动映射器多对一映射配置

本文关键字:映射 配置 多对一 | 更新日期: 2023-09-27 17:58:00

我想将3个不同的类映射到一个DTO中,每个属性在源和目标上都有相同的名称,类如下:

  • 用户
  • 候选人
  • 投资组合

这是DTO,以及我想如何映射我的对象:

public class CandidateTextInfo
    {
        public string ProfilePicture { get; set; }   //-->User
        public ObjectId UserId { get; set; }         //-->User
        public string Name { get; set; }             //--> Candidate
        public string Headline { get; set; }         //--> Candidate
        public Gender Gender { get; set; }           //--> Candidate
        public byte Rating { get; set; }             //--> Candidate
        public bool IsCompany { get; set; }          //--> Candidate
        public string[] Tags { get; set; }           //--> Portafolio
        public string[] Categories { get; set; }     //--> Portafolio
        public string ExecutiveSummary { get; set; } //--> Portafolio
        public HourlyRate HourlyRate{ get; set; }    //--> Candidate
    }

我一直在寻找SO,我找到了这个解决方案,但我没有得到方法ConstructUsing

那么我该怎么做才能有一个多对一的映射,如果没有任何变通方法的话,这可能吗?

自动映射器多对一映射配置

它在很大程度上取决于对象之间的关系。如果对象之间有1:1的关系(例如,如果User具有属性User.CandidateUser.Portfolio),则映射很容易:-

CreateMap<User, CandidateTextInfo>()
  .ForMember(d => d.ProfilePicture, o => o.MapFrom(s => s.ProfilePicture)
  // ...
  .ForMember(d => d.Name, o => o.MapFrom(s => s.Candidate.Name)
  // And so on...

如果你没有一对一的映射,你需要自己安排一点:-

public class CandidateTextInfoSource
{
  public CandidateTextInfoSource(User user,
                                 Candidate candidate,
                                 Portafolio portafolio)
  {
    this.User = user;
    this.Candidate = candidate;
    this.Portafolio = portafolio;
  }
  public User User { get; set; }
  public Candidate Candidate { get; set; }
  public Portafolio Portafolio { get; set; }
}
// ...
CreateMap<CandidateTextInfoSource, CandidateTextInfo>()
  .ForMember(d => d.ProfilePicture, o => o.MapFrom(s => s.User.ProfilePicture)
   // ...
  .ForMember(d => d.Name, o => o.MapFrom(s => s.Candidate.Name)
   // And so on...

然后,您可以根据对象之间的关系,使用所需的任何方法来创建CandidateTextInfoSource。例如,如果我假设User具有集合User.Candidates,而Candidate具有属性Candidate.Portfolio:-

CreateMap<User, IEnuemerable<CandidateTextInfoSource>>()
  .ConstructUsing(
    x => x.Candidates
          .Select(y => Mapper.Map<CandidateTextInfo>(new CandidateTextInfoSource(x, y, y.Portfolio)))
  .ToList());

我很感激这个答案来得很晚,但如果您进一步指定对象之间的关系,我可以帮助您创建更具体的映射。

Automapper的ConstructUsing对于从自定义代码构建一个属性非常有用。在你的情况下,这并不是真正的必要。您只需要创建从对象到DTO的映射。然后将每个对象实例映射到同一个DTO实例。

但是,由于Automapper希望定义目标对象的每个属性,以确保完全指定目标,因此需要将源对象中不存在的属性配置为忽略

CreateMap<Candidate, CandidateTextInfo>()
.ForMember(x=> x.ProfilePicture, opt => opt.Ignore())
.ForMember(... 
// repeat for all destination properties not existing in source properties

如果这是太多的样板代码,那么就会探索许多关于堆栈溢出的解决方案,其中这一个看起来很有前景:AutoMapper:"忽略其余的"?(看看Robert Schroeder的回答)