<p>EF Core无法对Oracle 19c JSON列使用LINQ查询(如Contains),因其Provider不支持将C# JSON操作翻译为JSON_VALUE/JSON_EXISTS函数,必须用FromSqlInterpolated配合显式SQL函数提取值。</p>
ef core 本身不识别 oracle 19c 的 json 列类型,无法直接映射或 linq 查询 json 字段;必须绕过 orm 层,用 fromsqlinterpolated 手写 sql + 显式类型转换才能安全取值。
为什么不能用 DbSet.Where(x => x.JsonField.Contains(...))?
EF Core 的 LINQ 翻译器(Oracle 提供的 EF Core Provider)至今不支持将 C# 对 JSON 字符串的操作(如 Contains、GetProperty)翻译成 Oracle 的 JSON_VALUE 或 JSON_EXISTS 函数。尝试这样写会直接报错:System.InvalidOperationException: The LINQ expression could not be translated。
- Provider 不识别
JSON类型字段,会把它当普通二进制或未知类型处理 - 即使字段在数据库中是
JSON类型,EF Core 模型里也得声明为string,但这样就丢掉了结构化查询能力 - 所有路径访问(如
.payload.id)、类型转换(如RETURNING NUMBER)、索引下推都必须由 SQL 层显式控制
FromSqlInterpolated 中如何正确提取 JSON 字段值?
核心是:在 SQL 里用 JSON_VALUE 或 JSON_QUERY + RETURNING 显式指定类型,并确保返回列有明确别名,EF Core 才能映射到 string、int? 等托管类型。
- ❌ 错误写法:
SELECT payload FROM orders WHERE id = {id}——payload是JSON类型,EF Core 取GetString()会失败或乱码 - ✅ 正确写法:
SELECT JSON_VALUE(payload, '$.amount' RETURNING NUMBER) AS amount FROM orders WHERE id = {id} - 若要取子对象或数组,用
JSON_QUERY(payload, '$.items'),返回仍是JSON类型,需再套一层JSON_SERIALIZE转字符串(尤其当源列是BLOB时) - 注意:路径表达式必须用单引号包裹,
$符号不能少,否则JSON_VALUE返回 NULL
从查询结果映射到 C# 对象要注意什么?
用 FromSqlInterpolated 时,EF Core 不走常规实体映射逻辑,而是按列名/顺序绑定到构造函数参数或属性。JSON 字段的“转换结果”必须和目标类型严格匹配。
- 如果 SQL 返回的是
JSON_VALUE(... RETURNING NUMBER),C# 属性必须是int?或decimal?,不能是string - 如果返回的是
JSON_SERIALIZE(JSON_QUERY(...)),那才是标准 JSON 字符串,可安全映射到string,再交给System.Text.Json解析 - 避免在 SQL 中拼接 JSON 字符串(如
'{' || ... || '}'),Oracle 19c 严格模式下非法格式会直接报ORA-40442 - NULL 值会被映射为 C# 的
null(对可空类型),不是空字符串或默认值
最易被忽略的一点:Oracle 的 JSON 列在查询时默认触发严格解析,哪怕只是 SELECT,只要内容不符合 RFC 7159(比如尾部多逗号、单引号字符串),就会在执行 SQL 阶段直接报错,而不是返回 NULL——这和 IS JSON CHECK 约束的行为完全不同。所以线上表如果有历史脏数据,FromSqlInterpolated 一查就崩,得先用 JSON_VALID 过滤或清理。


















