一、驱动。使用Oracle.ManagedDataAccess.Client

二、原理。利用OracleCommand的ArrayBindCount属性设置批量大小。

三、实现

函数使用的实体是efcore生成的实体,其字段命名法是帕斯卡命名法。

1.辅助函数

  1. public static DataTable ToDataTable<T>(List<T> items)
  2. {
  3. DataTable dataTable = new DataTable(typeof(T).Name);
  4.  
  5. // 获取所有属性
  6. var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
  7.  
  8. foreach (var prop in properties)
  9. {
  10. // 添加DataTable的列,列名为属性名
  11. dataTable.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
  12. }
  13.  
  14. foreach (var item in items)
  15. {
  16. var values = new object[properties.Length];
  17. for (int i = 0; i < properties.Length; i++)
  18. {
  19. // 通过反射获取属性值
  20. values[i] = properties[i].GetValue(item, null);
  21. }
  22. dataTable.Rows.Add(values);
  23. }
  24.  
  25. return dataTable;
  26. }
  27.  
  28. private static OracleDbType GetOracleType(Type type)
  29. {
  30. // 如果类型是可空类型,获取基础类型
  31. if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
  32. {
  33. type = Nullable.GetUnderlyingType(type);
  34. }
  35. // 添加更多类型的映射,以适应您的特定需求
  36. if (type == typeof(int))
  37. {
  38. return OracleDbType.Int32;
  39. }
  40. else if (type == typeof(string))
  41. {
  42. return OracleDbType.Varchar2;
  43. }
  44. else if (type == typeof(DateTime))
  45. {
  46. return OracleDbType.Date;
  47. }
  48. else if (type == typeof(decimal))
  49. {
  50. return OracleDbType.Decimal;
  51. }
  52. // 如果您有其他类型的映射需求,请在此处添加更多条件
  53.  
  54. // 默认情况下返回一个通用的值
  55. return OracleDbType.Varchar2; // 或者您认为合适的默认类型
  56. }
  57.  
  58. private static string ConvertPascalToSnakeCase(string input)
  59. {
  60. if (string.IsNullOrEmpty(input))
  61. {
  62. return input;
  63. }
  64.  
  65. string snakeCase = char.ToUpper(input[0]).ToString(); // 将首字母大写
  66.  
  67. for (int i = 1; i < input.Length; i++)
  68. {
  69. char currentChar = input[i];
  70. if (char.IsUpper(currentChar))
  71. {
  72. // 如果当前字符是大写字母,添加下划线并转换为小写
  73. snakeCase += "_";
  74. snakeCase += currentChar;
  75. }
  76. else
  77. {
  78. // 否则,直接添加字符
  79. snakeCase += char.ToUpper(currentChar);
  80. }
  81. }
  82.  
  83. return snakeCase;
  84. }
  85.  
  86. private static string GenerateInsertStatement(Type entityType, string tableName)
  87. {
  88. PropertyInfo[] properties = entityType.GetProperties();
  89.  
  90. string columns = string.Join(", ", properties.Select(p => ConvertPascalToSnakeCase(p.Name)));
  91. string values = string.Join(", ", properties.Select(p => $":{ConvertPascalToSnakeCase(p.Name)}"));
  92.  
  93. string insertStatement = $"INSERT INTO {tableName} ({columns}) VALUES ({values})";
  94.  
  95. return insertStatement;
  96. }
  97.  
  98. private static string GenerateUpdateStatement(Type entity, string tableName, string whereField)
  99. {
  100. PropertyInfo[] properties = entity.GetProperties();
  101.  
  102. // 生成 SET 部分,用于更新列
  103. string setClause = string.Join(", ", properties.Select(p => $"{ConvertPascalToSnakeCase(p.Name)} = :{ConvertPascalToSnakeCase(p.Name)}"));
  104. // 生成 WHERE 子句,基于指定的字段
  105. string whereClause = $"{ConvertPascalToSnakeCase(whereField)} = :{whereField}";
  106. string updateStatement = $"UPDATE {tableName} SET {setClause} WHERE {whereClause}";
  107.  
  108. return updateStatement;
  109. }

2.批量插入

  1. public static void BulkInsert<T>(List<T> entities, OracleConnection connection)
  2. {
  3. DataTable table = ToDataTable<T>(entities);
  4. try
  5. {
  6. string cmdstr = GenerateInsertStatement(typeof(T), ConvertPascalToSnakeCase(typeof(T).Name));
  7. using (OracleCommand command = new OracleCommand(cmdstr, connection))
  8. {
  9. command.ArrayBindCount = entities.Count; // 设置为批量操作的大小
  10. command.BindByName = true; // 使用参数名称绑定
  11. // 创建参数数组
  12. OracleParameter[] parameters = new OracleParameter[table.Columns.Count];
  13. for (int i = 0; i < table.Columns.Count; i++)
  14. {
  15. parameters[i] = new OracleParameter(ConvertPascalToSnakeCase(table.Columns[i].ColumnName), GetOracleType(table.Columns[i].DataType));
  16. // 选择特定列的所有行,并将其转换为数组
  17. object[] columnArray = table.AsEnumerable().Select(row => row.Field<object>(table.Columns[i].ColumnName)).ToArray();
  18. parameters[i].Value = columnArray;
  19. }
  20. // 添加参数到命令
  21. command.Parameters.AddRange(parameters);
  22. // 执行批量插入
  23. command.ExecuteNonQuery();
  24. }
  25. }
  26. catch (Exception e)
  27. {
  28. Console.WriteLine(e);
  29. }
  30. }

3.批量更新

  1. public static void BulkUpdate<T>(List<T> entities, OracleConnection connection, PropertyInfo keyField)
  2. {
  3. DataTable table = ToDataTable<T>(entities);
  4. try
  5. {
  6. string cmdstr = GenerateUpdateStatement(typeof(T), ConvertPascalToSnakeCase(typeof(T).Name), keyField.Name);
  7. using (OracleCommand command = new OracleCommand(cmdstr, connection))
  8. {
  9. command.ArrayBindCount = entities.Count; // 设置为批量操作的大小
  10. command.BindByName = true; // 使用参数名称绑定
  11. // 创建参数数组
  12. OracleParameter[] parameters = new OracleParameter[table.Columns.Count + 1];
  13. for (int i = 0; i < table.Columns.Count; i++)
  14. {
  15. parameters[i] = new OracleParameter(ConvertPascalToSnakeCase(table.Columns[i].ColumnName), GetOracleType(table.Columns[i].DataType));
  16. // 选择特定列的所有行,并将其转换为数组
  17. object[] columnArray = table.AsEnumerable().Select(row => row.Field<object>(table.Columns[i].ColumnName)).ToArray();
  18. parameters[i].Value = columnArray;
  19. }
  20. //where参数绑定
  21. parameters[table.Columns.Count] = new OracleParameter(keyField.Name, GetOracleType(keyField.PropertyType));
  22. object[] whereArray = table.AsEnumerable().Select(row => row.Field<object>(keyField.Name)).ToArray();
  23. parameters[table.Columns.Count].Value = whereArray;
  24. // 添加参数到命令
  25. command.Parameters.AddRange(parameters);
  26. // 执行批量插入
  27. command.ExecuteNonQuery();
  28. }
  29. }
  30. catch (Exception e)
  31. {
  32. Console.WriteLine(e);
  33. }
  34. }

四、用例

  1. //更新
  2. ExampleClass.BulkUpdate(delList, connection, typeof(实体类).GetProperty("实体主键字段"));
  3.  
  4. //插入
  5. ExampleClass.BulkInsert(addList, connection);

Oracle批量插入和更新的更多相关文章

  1. Mybatis 向oracle批量插入与更新数据

    插入 <insert id="batchSave" parameterType="java.util.List"> INSERT INTO T_UP ...

  2. oracle 批量插入-支持序列自增

    1.创建表.序列 -- Create table create table test_batch ( id number not null, name ), account ) ) -- Create ...

  3. java批量插入或更新的问题

    在批量插入或者更新中,setXXX的时候字段类型必须一致.例如:在普通sql中 pstmt8.setBigDecimal(j ,xxx);可以写成pstmt8.setString(j,xxx.toSt ...

  4. C#使用SqlDataAdapter 实现数据的批量插入和更新

    近日由于项目要求在需要实现中型数据的批量插入和更新,晚上无聊,在网上看到看到这样的一个实现方法,特摘抄过来,以便以后可能用到参考. 一.数据的插入 DateTime begin = DateTime. ...

  5. mybatis 注解的方式批量插入,更新数据

    一,当向数据表中插入一条数据时,一般先检查该数据是否已经存在,如果存在更新,不存在则新增  使用关键字  ON DUPLICATE KEY UPDATE zk_device_id为主键 model  ...

  6. MySQL on duplicate key update 批量插入并更新已存在数据

    业务上经常存在一种现象,需要批量往表中插入多条数据,但在执行过程中,很可能因为唯一键冲突,而导致批量插入失败.因此需要事先判断哪些数据是重复的,哪些是新增的.比较常用的处理方法就是找出已存在的数据,并 ...

  7. Mybatis中实现oracle的批量插入、更新

    oracle 实现在Mybatis中批量插入,下面测试可以使用,在批量插入中不能使用insert 标签,只能使用select标签进行批量插入,否则会提示错误 ### Cause: java.sql.S ...

  8. Oracle+Mybatis批量插入,更新和删除

    1.插入 (1)第一种方式:利用<foreach>标签,将入参的list集合通过UNION ALL生成虚拟数据,从而实现批量插入(验证过) <insert id="inse ...

  9. mybatis+oracle 批量插入,若数据库中有则做更新操作

    1.只批量插入: insert into WXPAY_ACCOUNT(id ,out_trade_no ,transaction_id)select SEQ_WXPAY_ACCOUNT.nextval ...

  10. mybatis Oracle 批量插入,批量更新

    传入的参数只要是list类型的参数就行了..............1.批量插入<insert id="insertBatch" parameterType="ja ...

随机推荐

  1. 如何实现OpenHarmony的OTA升级

    OTA简介 随着设备系统日新月异,用户如何及时获取系统的更新,体验新版本带来的新的体验,以及提升系统的稳定性和安全性成为了每个厂商都面临的严峻问题.OTA(Over the Air)提供对设备远程升级 ...

  2. 鸿蒙HarmonyOS实战-ArkUI组件(TextInput/TextArea)

    一.TextInput/TextArea TextInput和TextArea组件通常用于收集用户输入的文本数据. TextInput组件通常用于单行文本的输入,它允许用户通过一个光标来输入文字,并支 ...

  3. CMake 常用命令大全:提高项目构建效率

    CMake是一个跨平台.开源的构建工具,它可以自动生成Makefile或者Visual Studio等IDE的工程文件.它能够帮助开发者更方便地管理项目的构建过程,提高项目构建的效率.在本文中,我们将 ...

  4. 技术传递温度,HMS Core手语服务走进暖心课堂

    近日,华为HMS Core手语服务携手吉林大学.长春大学特教学院联合打造暖心课堂,在直播网课中加入AI手语翻译,于人文中融入科技,知识中融入温暖. 手语翻译:同学们大家好 HMS Core手语服务通过 ...

  5. 抓包整理————wireshark DNS 演练[三]

    前言 简单整理一些wireshark dns 演练. 正文 简单介绍一下什么是dns. 这个其实可以百度一下哈,其实就是将域名转换为ip. 然后查询过程是这样的: 根域名服务器 权威服务器 dns 被 ...

  6. mysql 必知必会整理—视图[十二]

    前言 简单整理一下视图. 正文 视图: 需要MySQL 5 MySQL 5添加了对视图的支持.因此,本章内容适用于MySQL 5及以后的版本. 视图是虚拟的表.与包含数据的表不一样,视图只包含使用时动 ...

  7. Java入门01:环境安装与配置

    Java入门01:环境安装与配置 JDK下载 下载地址:https://www.oracle.com/cn/java/technologies/javase/javase-jdk8-downloads ...

  8. 云原生 DevOps,模型化应用交付能力很重要!

    ​简介: DevOps 文化及其支撑其落地实践的自动化工具与平台能力在云原生架构渐为普及的背后,发挥了关键的价值. 撰稿:溪洋 云原生正在成为企业业务创新和解决规模化挑战的加速器. 云原生带来的变革绝 ...

  9. WPF 已知问题 Popup 失焦后导致 ListBox 无法用 MouseWheel 滚动问题和解决方法

    本文记录在 Popup 失焦后导致 ListBox 无法用 MouseWheel 滚动问题 原因: Popup虽然是个完整独立的窗体,但它的激活要靠它的"父窗口"间接来激活,这里之 ...

  10. WPF 双向绑定到非公开 set 方法属性在 NET 45 和 NET Core 行为的不同

    本文记录 WPF 在 .NET Framework 4.5 和 .NET Core 3.0 或更高版本对使用 Binding 下的 TwoWay 双向绑定模式绑定到非公开的 set 属性上的行为变更 ...