.NET升级至7+AutoMapper12时ProjectTo抛出'Default'类型LINQ异常
问题分析与解决方案
问题根源
升级到AutoMapper 12后,EF Core投影对可空导航属性的表达式生成逻辑发生了变化:
- 原始自动映射时,当
ProcessedBy为null,AutoMapper会生成default(ApplicationUserPreview)表达式,但EF Core无法解析这种Default类型的LINQ表达式,抛出Unknown LINQ expression of type 'Default'。 - 使用
DoNotAllowNull()时,若ApplicationUserPreview中存在非可空值类型属性(比如Guid Id而非Guid? Id),当数据库中ProcessedById为null时,EF尝试将null映射到非可空属性,就会触发cast to value type 'System.Guid' failed异常。
解决方案
方案1:修正DTO属性的可空性
检查ApplicationUserPreview的定义,确保所有从可空关联实体映射的属性都声明为可空类型:
public class ApplicationUserPreview { // 将非可空Guid改为可空 public Guid? Id { get; set; } // 其他可能为null的属性同理调整 public string? UserName { get; set; } }
之后使用AllowNull()配置映射:
CreateProjection<PaymentUpload, PaymentUploadDto>() .ForMember(dest => dest.ProcessedBy, opt => opt.AllowNull());
方案2:手动指定投影逻辑
通过MapFrom显式处理null情况,避免AutoMapper生成EF无法解析的默认表达式:
CreateProjection<PaymentUpload, PaymentUploadDto>() .ForMember(dest => dest.ProcessedBy, opt => opt.MapFrom(src => src.ProcessedBy == null ? null : new ApplicationUserPreview { Id = src.ProcessedBy.Id, UserName = src.ProcessedBy.UserName, // 映射其他需要的属性 }));
如果已经存在ApplicationUser到ApplicationUserPreview的映射配置,也可以结合ProjectTo复用:
CreateProjection<PaymentUpload, PaymentUploadDto>() .ForMember(dest => dest.ProcessedBy, opt => opt.MapFrom(src => src.ProcessedBy == null ? null : src.ProcessedBy.ProjectTo<ApplicationUserPreview>(Mapper.ConfigurationProvider)));
方案3:启用AutoMapper兼容模式(临时方案)
如果暂时不想修改大量代码,可以尝试启用AutoMapper旧版兼容行为,在全局配置中添加:
cfg.UseNullSubstituteForValueTypes = true;
注意:该选项可能在后续版本被移除,建议优先采用前两种方案。
内容的提问来源于stack exchange,提问作者JWrightII
相关产品推荐
相关产品推荐

