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;
        }
View Code
复制代码

 

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);
            }
        }
View Code
复制代码

 

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);
            }
        }
View Code
复制代码

 四、用例

//更新
ExampleClass.BulkUpdate(delList, connection, typeof(实体类).GetProperty("实体主键字段"));

//插入
ExampleClass.BulkInsert(addList, connection);

 

posted @   ggtc  阅读(378)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
//右下角目录
点击右上角即可分享
微信分享提示