DEBUG.WIKI
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
雨云;给项目一台云服务器
RackNerd;$21.99/年 · 1GB KVM

EF Core 10 表值函数配 ToJson,在查询编译时空引用

EF Core 10.0.3 的表值函数与 ToJson 组合可能在翻译期空引用,参数化 FromSqlRaw 可绕过入口,但复杂关联调用需另行验证。

同一个实体从普通表读取正常,从 [DbFunction] 声明的表值函数读取却失败,堆栈停在 AddJsonNavigationBindings。实体还有 OwnsOne() 或 OwnsMany() 的 ToJson() 映射时,应检查 EF Core 10.0.3 的这个组合回归。

它发生在关系型查询翻译阶段,SQL Server 提供程序有明确案例;换成 InMemory 提供程序不能验证这条路径。问题涉及表值函数实体的 JSON 类型映射缺失,查询翻译尝试为 JSON 导航建立绑定时遇到了空引用。此时反复修改连接字符串或提高连接超时,无法补上模型映射。

临时绕过函数映射入口

原有函数封装可能是:

[DbFunction(Name = "GetControls", Schema = "app")]
public IQueryable<Control> GetControls(Guid userId)
    => FromExpression(() => GetControls(userId));

在受影响组合中,可以改为从实体集合进入参数化 SQL 路径:

public IQueryable<Control> GetControls(Guid userId)
    => Set<Control>().FromSqlRaw(
        "SELECT * FROM app.GetControls({0})", userId);

这里的 {0} 与单独传入的 userId 会形成参数,不能先用字符串插值把值拼进 FromSqlRaw()。函数和 schema 名称应由代码固定,也不要把外部输入当作数据库标识符直接拼接。

这个办法保留函数返回的实体及 JSON 映射,改变的是查询入口。返回列必须满足 Control 的映射要求,特别是主键与 JSON 容器列;如果普通 FromSql 查询本身就缺列,它仍会失败。

验收原有查询的组合能力

先在测试环境查看新入口的 ToQueryString(),确认能够生成 SQL,参数仍是参数。随后验证原有过滤、排序以及 JSON 成员读取,核对返回行数和实际字段值,而不只确认空引用消失。

简单函数调用的替代不代表所有复杂 LINQ 都能原样搬过去。函数参数若取自外层查询的另一行,形成相关调用或 lateral join,单独的 Set<Control>().FromSqlRaw(...) 不会自动保留相同关联语义。不能为了避开异常就逐行补查,再把它当作等价、高效的方案。

这项回归的修补被放入后续大版本开发路径,不能把开发分支或 11.0 预发布包说成已经可用于生产的正式修复。对 EF Core 10.0.3,这里采用的是已确认的参数化 SQL 绕法;以后迁移回函数映射时,也应重新验证相同查询及数据,避免只按版本号删除兼容代码。