EF Core 10 嵌套 JSON 查询报 CreateJsonShapers 的 key 为空
EF Core 10 与命名插件的嵌套 JSON 查询可能因名称为空而失败,显式配置 HasJsonPropertyName 时须保留已有 JSON 键名。
实体使用 OwnsOne()、OwnsMany() 和 ToJson() 映射嵌套数据,查询时却在 CreateJsonShapers 抛出 ArgumentNullException: Value cannot be null. (Parameter 'key')。如果项目还启用了 EFCore.NamingConventions 的命名规则,应同时检查嵌套 JSON 成员名称。
这个组合在 EF Core 10.0.1 的查询中有明确案例。不同 RC 与正式版插件的行为并不完全一致,不能仅凭“EF Core 10”就认定所有版本都触发。典型机制是命名插件在拥有类型上添加容器列注解,EF Core 解析 JSON 元数据时拿不到预期的嵌套名称,随后将空值用作字典键。数据库连接尚未真正执行查询时,编译路径也可能先失败。
给嵌套成员明确的 JSON 名称
对于已经确认属于这条路径的模型,可以为嵌套拥有类型显式设置 HasJsonPropertyName():
modelBuilder.Entity<Order>().OwnsMany(x => x.Items, items =>
{
items.ToJson();
items.OwnsOne(x => x.Period, period =>
{
period.HasJsonPropertyName("Period");
});
});
示例中的 Order、Items、Period 对应应用已有模型;"Period" 必须替换为已有 JSON 文档真正使用的键。它不是数据库列名,也不能因为启用了 snake case 就随手改成 "period"。JSON 键名的变化会影响存量文档读取,消除异常却读出空成员,同样不算解决。
先定位出错的嵌套层,再给这一层明确名称,不必把整个模型的所有字段重新命名。这个配置办法已有实际确认,但不能据此承诺某个后续 EF Core 或命名插件版本已完成全面修复。
比较模型名称,也比较读出的数据
可以先用 ToQueryString() 查看受影响查询能否完成关系型查询编译,然后在测试数据上检查嵌套对象及集合中的具体值。仅看查询不再抛异常,可能漏掉键名与存量 JSON 不一致的问题。
对照检查应保留相同的实体、数据和查询,只改变待验证的 JSON 名称配置。若短期关闭命名规则,生成的数据库列名、表名和迁移也可能发生变化;不要把这种大范围变更作为默认绕法,更不要立即应用由此产生的迁移。
如果没有使用命名插件,或者空键出现在另一条堆栈路径,应继续查具体模型,不要给无关层级强塞名称。表值函数与 JSON 映射组合引起的 AddJsonNavigationBindings 空引用,也不属于这个嵌套名称问题,处理方法需要另行判断。


