You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

EF Core中可为空Owned类型配置问题咨询

EF Core 支持可为空的 Owned 类型吗?

当然支持!EF Core从3.0版本开始就完全支持可为空的Owned类型了,你遇到的保存报错和查询时的非null问题,都是因为配置或使用细节没处理对,我来帮你一步步搞定:

1. 解决保存时的 InvalidOperationException 报错

你碰到的这个报错,本质是EF Core在处理新增的Member实体时,默认会期望关联的Address Owned实体也处于Added状态,但你把Address设为null了,导致它找不到匹配键值的Owned实体,所以抛出了冲突错误。

要解决这个问题,你需要做两件事:

  • 确保主实体Member中的Address导航属性是可空的:如果用的是C# 8+的可空引用类型,直接声明成public StreetAddress? Address { get; set; };如果没开可空上下文,保持public StreetAddress Address { get; set; }但允许赋值为null就行。
  • OwnsOne的配置里,显式标记这个导航属性可为空(EF Core 5+会自动识别可空导航,3.x版本需要手动加):
map.OwnsOne(x => x.Address, cb => 
{
    cb.OwnsOne(l => l.Location);
    // 显式指定Address导航不需要强制存在
    cb.Navigation(x => x.Address).IsRequired(false);
});

另外,赶紧把构造函数里强制实例化AddressLocation的代码删掉——这正是你查询时总是得到非null Address的原因,让Address能自然地被设为null。

2. 让查询时自动返回null的Owned实体

如果你的EF Core版本是5.0及以上,那恭喜你,不需要额外操作:当数据库中Address的所有属性全是null时,EF Core会自动把MemberAddress导航属性设为null。

要是你还在使用EF Core 3.x,EF Core不会自动处理这种情况,查询时会返回一个所有属性都是null的Address实例。这时候你可以手动处理:

  • 要么在查询后遍历结果,检查Address的所有属性是否都为null,是的话就把Address设为null;
  • 要么用投影查询直接控制返回结果:
var members = context.Members
    .Select(m => new Member
    {
        Id = m.Id,
        // 把Member的其他属性也加上
        Address = m.Address?.Location == null && string.IsNullOrEmpty(m.Address?.Street) && /* 检查Address的所有其他属性 */
            ? null 
            : m.Address
    })
    .ToList();

总结一下

  • EF Core完全支持可为空的Owned类型,核心就是确保导航属性可空,配置正确;
  • 保存时别强制实例化Owned实体,让它能自然为null;
  • EF Core 5+会自动处理全null的Owned实体,低版本需要手动补一下逻辑。

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

火山引擎 最新活动