OracleBulkCopy.WriteToServer 遇 NULL 值直接报 ORA-01400,需显式设 DataTable.Columns["ColName"].AllowDBNull = true;DATE 类型需清理毫秒并用 DateTime? 赋 null;复杂 NULL 场景推荐 ArrayBindCount 批量插入。

OracleBulkCopy.WriteToServer 会因 NULL 值直接报 ORA-01400,不是跳过或提示哪一行——必须提前确保 DataTable 列允许 NULL,且目标字段定义为 NULLABLE。
DataTable 列的 AllowDBNull 必须显式设为 true
OracleBulkCopy 不会读取目标表结构自动推断可空性,它只按 DataTable 的元数据判断。哪怕 Oracle 表字段定义为 NULL,只要 DataTable.Columns["ColName"].AllowDBNull == false,遇到 null 值就会整批失败。
- 对所有可能含
null的列,插入前执行:dt.Columns["ColName"].AllowDBNull = true - 不要依赖
DataTable.Load()的自动推断——它常把数据库NULL列误设为AllowDBNull = false - 若用
DataTable.ReadXml()或手动Columns.Add(),务必补上AllowDBNull = true
DATE 类型 NULL 和精度问题必须分开处理
Oracle 的 DATE 类型不存毫秒,但 .NET 的 DateTime? 含毫秒且可为 null。这两者叠加时,ORA-01400 和 ORA-01830 可能同时出现,且错误堆栈不指明根源。
- 先统一清理毫秒:
dtValue = dtValue.AddTicks(-dtValue.Ticks % TimeSpan.TicksPerSecond),再赋值给 DataRow - 对
DateTime?列,null值必须写入,不能用DateTime.MinValue替代(Oracle 会转成0001-01-01,触发约束) - 连接字符串里的
DateTime=1对OracleBulkCopy无效,别白配 - 更稳方案:改用
OracleDbType.TimeStamp,并配OracleBulkCopy.ColumnMappings显式指定类型
替代方案:ArrayBindCount 批量插入更适合可控 NULL 场景
当数据中 NULL 分布复杂、或需逐行校验逻辑时,OracleBulkCopy 的“全有或全无”特性反而拖累调试。此时 ArrayBindCount + 参数化 INSERT 更灵活。
-
cmd.ArrayBindCount = rowCount是关键,不设则退化为单行执行 - 每个参数数组元素可独立为
DBNull.Value,Oracle 驱动原生支持 - 示例中
delayedT[i] = ... ? decimal.Parse(...) : (decimal?)null→ 赋值前转成object数组,null自动映射为DBNull.Value - 注意:所有参数数组长度必须一致,否则
ExecuteNonQuery()报ORA-01036
真正麻烦的不是 NULL 本身,而是 OracleBulkCopy 把类型校验、约束检查、甚至 NLS 格式都压到提交那一刻才爆发——出错时你既看不到是第几行,也分不清是类型错还是值错。动手前先用 10 行测试数据跑通全流程,比后期查日志快得多。


















