<p>Oracle 23c 的 JSON 类型在 C# 中无法直接映射,ODP.NET 当前版本仅将其识别为 Varchar2 或 Clob,需手动处理序列化、预检验证(JSON_VALID)、SQL 层解析(JSON_VALUE/JSON_QUERY)、语义比较(JSON_EQUAL)及批量写入(JSON_ARRAY + ArrayBinding)。</p>

Oracle23c 的 JSON 数据类型在 C# 中不能直接映射
Oracle 23c 原生支持 JSON 类型(非 VARCHAR2 或 CLOB),但 Oracle Data Provider for .NET(ODP.NET)当前版本(23.5 及之前)仍不识别该类型为独立 .NET 类型。执行 SELECT 时,JSON 列会以 OracleDbType.Varchar2 或 OracleDbType.Clob 返回,具体取决于长度和驱动行为;插入时若直接传入字符串,Oracle 会隐式验证并转为 JSON 值——但你无法靠类型系统获得编译期保障或自动解析。
这意味着:你得手动处理序列化/反序列化,且必须显式启用 JSON 验证逻辑(否则写入非法 JSON 不报错,只在查询时报 ORA-40442: JSON syntax error)。
- 用
OracleParameter绑定 JSON 字符串时,务必设OracleDbType = OracleDbType.Varchar2(短 JSON)或OracleDbType.Clob(长 JSON),避免依赖默认推断 - 插入前建议用
OracleCommand执行SELECT JSON_VALID(:json_str) FROM DUAL预检,值为1才继续,否则抛ArgumentException - 不要依赖
DataTable.Load()自动识别 JSON 列——它只会当普通字符串读取
用 JSON_VALUE 和 JSON_QUERY 在 SQL 层提取字段,避免 C# 解析开销
如果只需查某个嵌套字段(如 user.profile.age),别把整段 JSON 拉到 C# 再用 System.Text.Json.JsonDocument 解析。Oracle 23c 支持标准 SQL/JSON 路径表达式,性能更好、也规避了 .NET 端 JSON 库的兼容性问题。
示例:从 orders 表的 metadata JSON 列中取支付方式
SELECT id, JSON_VALUE(metadata, '$.payment.method') AS payment_method FROM orders WHERE JSON_VALUE(metadata, '$.status') = 'completed'
在 C# 中绑定参数时注意:
-
JSON_VALUE返回标量(VARCHAR2),可用GetString()直接读取 -
JSON_QUERY返回 JSON 子文档(仍是CLOB或VARCHAR2),需再解析——除非你把它当字符串透传给前端 - 路径表达式中的单引号必须双写(
'')或用 @ 字符串避免 C# 转义干扰
IS JSON 约束 + JSON_EQUAL 是唯一可靠的 JSON 比较方式
Oracle 23c 允许建表时加 CHECK (col IS JSON),但 C# 层做更新判断时,不能用 string.Equals(oldJson, newJson)——JSON 键序、空格、换行不同就会误判。也不能用 DBMS_LOB.COMPARE,因为 JSON 的语义相等 ≠ 字节相等。
正确做法是交由 Oracle 执行语义比较:
SELECT CASE WHEN JSON_EQUAL(:old, :new) THEN 1 ELSE 0 END FROM DUAL
绑定两个 OracleParameter,类型均为 OracleDbType.Varchar2 或 Clob,值为格式化后的 JSON 字符串(推荐用 JsonSerializer.Serialize(obj, new JsonSerializerOptions { WriteIndented = false }) 统一格式)。
-
JSON_EQUAL忽略键序、空白、重复键(后者取最后值),符合 JSON RFC 标准 - 若字段含二进制数据(Base64)、时间戳(ISO 8601 字符串),
JSON_EQUAL仍能正确比对 - 别用
TO_CLOB()包裹参数——ODP.NET 会自动处理 CLOB 绑定,多包一层反而触发隐式转换失败
批量写入 JSON 时,ArrayBinding 配合 JSON_ARRAY 函数最省事
要一次插入多条带 JSON 的记录,别循环执行 INSERT。ODP.NET 支持数组绑定(OracleCommand.ArrayBindCount),配合 Oracle 23c 的 JSON_ARRAY 可构造内联 JSON 数组。
例如批量插入用户偏好设置:
INSERT INTO user_prefs (user_id, prefs) VALUES (:ids, JSON_ARRAY(:prefs FORMAT JSON))
然后在 C# 中:
- 声明
int[] ids = { 101, 102, 103 };和string[] prefs = { "{\"theme\":\"dark\"}", "{\"lang\":\"zh\"}", "{\"notify\":true}" }; - 创建两个
OracleParameter,CollectionType = OracleCollectionType.PLSQLAssociativeArray - 设
cmd.ArrayBindCount = ids.Length,执行即完成批量插入 - 注意:
JSON_ARRAY(... FORMAT JSON)会验证每个元素是否合法 JSON,任一非法则整批失败
真正容易被忽略的是:Oracle 对 JSON_ARRAY 输入的字符串要求严格——必须是已转义好的 JSON 字符串字面量,不能是原始 C# 对象。你得先序列化再传,而不是指望 Oracle 帮你“理解”对象结构。


















