【问题标题】:How to Conditionally MapFrom in Automapper using ProjectTo如何在 Automapper 中使用 ProjectTo 有条件地 MapFrom
【发布时间】:2021-07-14 18:48:27
【问题描述】:

我想使用 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));

  }
}

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

查询

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。

【问题讨论】:

  • @LucianBargaoanu 这似乎实现了我的目标!我唯一不清楚的部分(来自文档)是我需要在每个成员上设置ExplicitExpansion

标签: .net-core entity-framework-core automapper


【解决方案1】:

在他们的评论中参考通过@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);

【讨论】:

    猜你喜欢
    • 2013-01-16
    • 1970-01-01
    • 2019-07-24
    • 2020-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-15
    • 2021-01-27
    相关资源
    最近更新 更多