如何使用 ProjectTo 在 Automapper 中有条件地 MapFrom

How to Conditionally MapFrom in Automapper using ProjectTo

我想使用来自 Automapper 10.1.1 的投影为 EFCore 5 创建一个查询,该查询将有条件地包含关联。 如果我将其写在 select 语句中,我将执行以下操作:

_dbContext.Employees
.Select(x => new EmployeeDto()
{
 Id = x.Id,
 Contract = includeContract ? new ContractDto()
 {
  Id = x.Contract.Id
 } : null
})
.FirstAsync();

我是这样尝试的:

型号

//Source
  public class Employee
  {
    public int Id { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
    public Contract ActiveContract { get; set; }
  }

  public class Contract
  {
    public int Id { get; set; }
    public DateTimeOffset StartDate { get; set; }
    public DateTimeOffset EndDate { get; set; }
    public Employee Employee { get; set; }
    public int EmployeeId { get; set; }
  }


//Destination
  public class EmployeeDto
  {
    public int Id { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
    public ContractDto ActiveContract { get; set; }
  }

  public class ContractDto
  {
    public int Id { get; set; }
    public DateTimeOffset StartDate { get; set; }
    public DateTimeOffset EndDate { get; set; }
  }

AutoMapper 配置文件

public class EmployeeProfile : Profile
{
  public EmployeeProfile()
  {
    bool includeContract = false;

    CreateMap<Employee, EmployeeDto>()
    .ForMember(x => x.ActiveContract, opt => opt.MapFrom(x => includeContract ? x.ActiveContract : null));

  }
}

而不是 null,我尝试了 default(Contract)(Contract)null 它们产生相同的结果。 我还有一个合同映射,只是一个简单的 <Contract, ContractDto>.

查询

bool includeContract = someCondition;
var result = await _dbContext.Employees
      .ProjectTo<EmployeeDto>(_mapper.ConfigurationProvider, new { includeContract })
      .FirstAsync(x => x.id == id);

我的预期结果是,除非 includeContract 设置为 true,否则我将返回一个 EmployeeDto 合同为空。

但是,如果 includeContract 为假,则会抛出以下错误:

System.InvalidOperationException: Expression 'NULL' in SQL tree does not have type mapping assigned

生成的查询表达式:

       Compiling query expression: 
       'DbSet<Employee>()
           .Select(dtoEmployee => new EmployeeDto{ 
               Age = dtoEmployee.Age, 
               Id = dtoEmployee.Id, 
               Name = dtoEmployee.Name, 
               ActiveContract = null == null ? null : new ContractDto{ 
                   Id = null.Id, 
                   StartDate = null.StartDate, 
                   EndDate = null.EndDate 
               }
                
           }
           )
           .First(x => x.Id == __id_0)'

我知道这可以通过在 ConvertUsing 中显式定义表达式来实现,但我希望尽可能避免写出我的整个 DTO。

在他们的评论中引用通过@Lucian 链接的文档。

解决方案是将 AutoMapper 配置调整为以下内容:

CreateMap<Employee, EmployeeDto>()
.ForMember(x => x.ActiveContract, opt => opt.ExplicitExpansion())

并将查询调整为以下内容:

var result = await _dbContext.Employees
.ProjectTo<EmployeeDto>(_mapper.ConfigurationProvider, 
  null,
  dest => dest.ActiveContract
)
.FirstAsync(x => x.id == id);