OracleDynamicParameters需显式配置类型与集合参数:IN子句须用PLSQLAssociativeArray+自定义表类型;重复参数名需多次Add;RETURNING须用Output参数;TIMESTAMP WITH TIME ZONE必须用DateTimeOffset+TimeStampTZ。
OracleDynamicParameters 为什么不能直接传 List
oracle 的 in 子句不支持 dapper 默认的数组参数展开,比如 where id in @ids 配合 new { ids = new[] { 1, 2, 3 } } 在 oracle 下会报 ora-01722: invalid number 或静默失败——因为 oracledynamicparameters 并不会自动把 c# 数组转成 oracle 的 `table()` 集合类型。
必须显式构造 Oracle 兼容的集合参数:
-
OracleDynamicParameters需要配合OracleDbType.Int32+OracleCollectionType.PLSQLAssociativeArray - 对应 PL/SQL 中声明的关联数组类型(如
sys.ODCINumberList不行,它不支持下标访问;得用自定义或DBMS_SQL.VARCHAR2_TABLE类型) - 实际常用的是
OracleDbType.Varchar2或Int32配OracleCollectionType.PLSQLAssociativeArray,且需确保数据库端有对应 type(如CREATE OR REPLACE TYPE num_list AS TABLE OF NUMBER;)
怎么正确绑定多个同名参数(比如 :status 多次出现)
Dapper 默认不允许重复参数名,但 Oracle 原生 SQL 经常需要多次引用同一参数(例如 WHERE status = :status AND updated_by = :status)。直接传 new { status = "A" } 会抛 ORA-01036: illegal variable name/number。
解决方法是用 OracleDynamicParameters 显式添加多次:
var p = new OracleDynamicParameters();
p.Add(":status", "A", OracleDbType.Varchar2, ParameterDirection.Input);
p.Add(":status", "A", OracleDbType.Varchar2, ParameterDirection.Input); // 第二次添加,Dapper 不报错
⚠️ 注意:这依赖 Oracle 官方驱动对重复绑定名的支持(Oracle.ManagedDataAccess ≥ 19.10),旧版本可能仍失败;更稳的方式是改写 SQL 用不同名(:status1, :status2)再统一赋值。
执行含 RETURNING 子句的 INSERT 并获取返回值
Oracle 支持 INSERT ... RETURNING id INTO :new_id,但 Dapper 的 Query<T> 或 Execute 无法直接映射 RETURNING 变量。必须用 OracleDynamicParameters 声明输出参数,并调用 Execute(不是 Query):
var p = new OracleDynamicParameters();
p.Add(":name", "test", OracleDbType.Varchar2, ParameterDirection.Input);
p.Add(":new_id", dbType: OracleDbType.Int32, direction: ParameterDirection.Output);
<p>conn.Execute("INSERT INTO users(name) VALUES (:name) RETURNING id INTO :new_id", p);
int newId = p.Get<int>(":new_id");
关键点:
-
RETURNING后的变量名(:new_id)必须和Add()中的参数名完全一致(包括冒号) - 必须用
ParameterDirection.Output,且类型要和列类型严格匹配(比如NUMBER(10)对应OracleDbType.Int32,非Int64) - 不能用
QuerySingle<int>,否则 Oracle 驱动不识别 RETURNING 上下文
日期参数传入时区问题(特别是 TIMESTAMP WITH TIME ZONE)
Oracle 的 TIMESTAMP WITH TIME ZONE 列,如果用 DateTime.Now 直接传参,Dapper 默认走 OracleDbType.TimeStamp,会丢失时区信息,导致查出时间偏移错误。
正确做法是:
- 用
OracleDbType.TimeStampTZ显式指定类型 - 参数值必须是
DateTimeOffset,不能是DateTime - 确保连接字符串中包含
Unicode=True和Pooling=False(部分版本下 Pooling 会复用时区上下文)
示例:
var p = new OracleDynamicParameters();
p.Add(":created_at", new DateTimeOffset(DateTime.UtcNow), OracleDbType.TimeStampTZ);
conn.Query("SELECT * FROM events WHERE created_at > :created_at", p);
漏掉 DateTimeOffset 或错用 OracleDbType.TimeStamp 是最隐蔽的时序 bug 来源——表面查得出来,但跨时区部署后数据就对不上。


















