Oracle批量插入和更新
一、驱动。使用Oracle.ManagedDataAccess.Client
二、原理。利用OracleCommand的ArrayBindCount属性设置批量大小。
三、实现
函数使用的实体是efcore生成的实体,其字段命名法是帕斯卡命名法。
1.辅助函数

public static DataTable ToDataTable<T>(List<T> items) { DataTable dataTable = new DataTable(typeof(T).Name); // 获取所有属性 var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance); foreach (var prop in properties) { // 添加DataTable的列,列名为属性名 dataTable.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType); } foreach (var item in items) { var values = new object[properties.Length]; for (int i = 0; i < properties.Length; i++) { // 通过反射获取属性值 values[i] = properties[i].GetValue(item, null); } dataTable.Rows.Add(values); } return dataTable; } private static OracleDbType GetOracleType(Type type) { // 如果类型是可空类型,获取基础类型 if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) { type = Nullable.GetUnderlyingType(type); } // 添加更多类型的映射,以适应您的特定需求 if (type == typeof(int)) { return OracleDbType.Int32; } else if (type == typeof(string)) { return OracleDbType.Varchar2; } else if (type == typeof(DateTime)) { return OracleDbType.Date; } else if (type == typeof(decimal)) { return OracleDbType.Decimal; } // 如果您有其他类型的映射需求,请在此处添加更多条件 // 默认情况下返回一个通用的值 return OracleDbType.Varchar2; // 或者您认为合适的默认类型 } private static string ConvertPascalToSnakeCase(string input) { if (string.IsNullOrEmpty(input)) { return input; } string snakeCase = char.ToUpper(input[0]).ToString(); // 将首字母大写 for (int i = 1; i < input.Length; i++) { char currentChar = input[i]; if (char.IsUpper(currentChar)) { // 如果当前字符是大写字母,添加下划线并转换为小写 snakeCase += "_"; snakeCase += currentChar; } else { // 否则,直接添加字符 snakeCase += char.ToUpper(currentChar); } } return snakeCase; } private static string GenerateInsertStatement(Type entityType, string tableName) { PropertyInfo[] properties = entityType.GetProperties(); string columns = string.Join(", ", properties.Select(p => ConvertPascalToSnakeCase(p.Name))); string values = string.Join(", ", properties.Select(p => $":{ConvertPascalToSnakeCase(p.Name)}")); string insertStatement = $"INSERT INTO {tableName} ({columns}) VALUES ({values})"; return insertStatement; } private static string GenerateUpdateStatement(Type entity, string tableName, string whereField) { PropertyInfo[] properties = entity.GetProperties(); // 生成 SET 部分,用于更新列 string setClause = string.Join(", ", properties.Select(p => $"{ConvertPascalToSnakeCase(p.Name)} = :{ConvertPascalToSnakeCase(p.Name)}")); // 生成 WHERE 子句,基于指定的字段 string whereClause = $"{ConvertPascalToSnakeCase(whereField)} = :{whereField}"; string updateStatement = $"UPDATE {tableName} SET {setClause} WHERE {whereClause}"; return updateStatement; }
2.批量插入

public static void BulkInsert<T>(List<T> entities, OracleConnection connection) { DataTable table = ToDataTable<T>(entities); try { string cmdstr = GenerateInsertStatement(typeof(T), ConvertPascalToSnakeCase(typeof(T).Name)); using (OracleCommand command = new OracleCommand(cmdstr, connection)) { command.ArrayBindCount = entities.Count; // 设置为批量操作的大小 command.BindByName = true; // 使用参数名称绑定 // 创建参数数组 OracleParameter[] parameters = new OracleParameter[table.Columns.Count]; for (int i = 0; i < table.Columns.Count; i++) { parameters[i] = new OracleParameter(ConvertPascalToSnakeCase(table.Columns[i].ColumnName), GetOracleType(table.Columns[i].DataType)); // 选择特定列的所有行,并将其转换为数组 object[] columnArray = table.AsEnumerable().Select(row => row.Field<object>(table.Columns[i].ColumnName)).ToArray(); parameters[i].Value = columnArray; } // 添加参数到命令 command.Parameters.AddRange(parameters); // 执行批量插入 command.ExecuteNonQuery(); } } catch (Exception e) { Console.WriteLine(e); } }
3.批量更新

public static void BulkUpdate<T>(List<T> entities, OracleConnection connection, PropertyInfo keyField) { DataTable table = ToDataTable<T>(entities); try { string cmdstr = GenerateUpdateStatement(typeof(T), ConvertPascalToSnakeCase(typeof(T).Name), keyField.Name); using (OracleCommand command = new OracleCommand(cmdstr, connection)) { command.ArrayBindCount = entities.Count; // 设置为批量操作的大小 command.BindByName = true; // 使用参数名称绑定 // 创建参数数组 OracleParameter[] parameters = new OracleParameter[table.Columns.Count + 1]; for (int i = 0; i < table.Columns.Count; i++) { parameters[i] = new OracleParameter(ConvertPascalToSnakeCase(table.Columns[i].ColumnName), GetOracleType(table.Columns[i].DataType)); // 选择特定列的所有行,并将其转换为数组 object[] columnArray = table.AsEnumerable().Select(row => row.Field<object>(table.Columns[i].ColumnName)).ToArray(); parameters[i].Value = columnArray; } //where参数绑定 parameters[table.Columns.Count] = new OracleParameter(keyField.Name, GetOracleType(keyField.PropertyType)); object[] whereArray = table.AsEnumerable().Select(row => row.Field<object>(keyField.Name)).ToArray(); parameters[table.Columns.Count].Value = whereArray; // 添加参数到命令 command.Parameters.AddRange(parameters); // 执行批量插入 command.ExecuteNonQuery(); } } catch (Exception e) { Console.WriteLine(e); } }
四、用例
//更新 ExampleClass.BulkUpdate(delList, connection, typeof(实体类).GetProperty("实体主键字段")); //插入 ExampleClass.BulkInsert(addList, connection);
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律