You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决Automapper与EF Core中的‘Nullable object must have a value’错误

解决Automapper映射时Nullable object must have a value错误

问题场景

开发Blazor Server应用时,为OrderDetail实体新增了可空的ShippingWeek字段,但使用Automapper的ProjectTo方法将Order实体映射到OrderDto时,抛出System.InvalidOperationException: Nullable object must have a value错误。

相关代码片段

OnInitializedAsync中的映射代码:

IQueryable<OrderDto?> _ordersDto = Mapper.ProjectTo<OrderDto>(_order);

Order与OrderDto的Automapper配置:

CreateMap<Order, OrderDto>()
    .ForMember(dest => dest.OrderDetailsDto, opt => opt.MapFrom(src => src.OrderDetails))
    .ForMember(dest => dest.Customer, opt => opt.MapFrom(src => src.Customer))
    .ForAllMembers(opts =>
    {
        opts.Condition((src, dest, srcMember) => srcMember != null);
    });

简化后的实体与DTO类:

public class Order
{
    public int Id { get; set; }    
    public List<OrderDetail> OrderDetails { get; set; }   
}

public class OrderDto
{
    public int Id { get; set; }    
    public List<OrderDetailDto> OrderDetailsDto { get; set; }   
}

public class OrderDetail
{
    public int Id { get; set; }
    public string? Currency { get; set; }
    public int OrderId { get; set; }
    public Order Order { get; set; }
    public int ShippingWeek { get; set; } // 声明为非可空,但实际数据库字段为可空
}

public class OrderDetailDto
{
    public int Id { get; set; }
    public string? Currency { get; set; }
    public int OrderId { get; set; }
    public OrderDto OrderDto { get; set; }
    public int ShippingWeek { get; set; } // 对应实体的非可空类型
}

OrderDetail与OrderDetailDto的映射配置:

CreateMap<OrderDetail, OrderDetailDto>()
    .ForMember(dest => dest.OrderDto, opt => opt.MapFrom(src => src.Order))
    .ForMember(dest => dest.VendorDto, opt => opt.MapFrom(src => src.Vendor))
    .ForMember(dest => dest.ShippingWeek, opt => opt.MapFrom(src => src.ShippingWeek))
    .ForAllMembers(opts =>
    {
        opts.Condition((src, dest, srcMember) => srcMember != null);
    });

问题根源

  1. 类型不匹配:OrderDetail实体的ShippingWeek声明为非可空int,但实际数据库字段是可空的,EF Core查询时会将数据库的null值尝试赋值给非可空int,引发错误。
  2. Automapper条件限制:ForAllMembers中的srcMember != null条件对非可空值类型(如int)永远为true,但当数据库返回null时,Automapper无法将null映射到非可空int类型的DTO字段。

解决方案

1. 修正实体与DTO的字段类型

将OrderDetail和OrderDetailDto中的ShippingWeek改为可空int,与数据库字段的可空性保持一致:

public class OrderDetail
{
    // 其他字段不变
    public int? ShippingWeek { get; set; } // 修改为可空类型
}

public class OrderDetailDto
{
    // 其他字段不变
    public int? ShippingWeek { get; set; } // 同步改为可空类型
}

2. 调整Automapper映射条件

针对可空值类型调整ForAllMembers的条件,允许null值映射:

CreateMap<OrderDetail, OrderDetailDto>()
    .ForMember(dest => dest.OrderDto, opt => opt.MapFrom(src => src.Order))
    .ForMember(dest => dest.VendorDto, opt => opt.MapFrom(src => src.Vendor))
    .ForAllMembers(opts =>
    {
        // 允许可空值类型的null被映射,同时过滤引用类型的null
        opts.Condition((src, dest, srcMember) => 
            srcMember != null || 
            (srcMember is ValueType && Nullable.GetUnderlyingType(srcMember.GetType()) != null));
    });

如果仅需跳过引用类型的null,可简化条件:

.ForAllMembers(opts =>
{
    opts.Condition((src, dest, srcMember) => 
        srcMember == null ? false : !srcMember.GetType().IsValueType);
});

3. 移除不必要的单独字段映射

由于ShippingWeek字段名在实体和DTO中一致,可移除单独的ForMember配置,Automapper会自动匹配映射。

验证

修改完成后,重新运行ProjectTo映射,即可正常处理ShippingWeek为null的场景,不再抛出错误。

内容的提问来源于stack exchange,提问作者raysefo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 10:17:05