自曾列就别往下看 别折腾了  

使用 SqlBulkCopy ,dataTable 必须跟sql里面的表字段完全一样

下面在sqlserver中演示

mysql 请google MySqlBulkLoader

oracle 请google OracleBulkCopy

表结构

        DROP TABLE [dbo].[Product]
GO
CREATE TABLE [dbo].[Product] (
[Id] varchar(36) NOT NULL ,
[Name] varchar(255) NOT NULL ,
[Price] decimal(18,4) NOT NULL
)
GO
ALTER TABLE [dbo].[Product] ADD PRIMARY KEY ([Id])
GO

批量添加

        public static void Insert<T>(string connectionString, List<T> dataList, string destinationTableName, int batchSize = )
{
DataTable dataTable = ConvertToDataTable(dataList);
Insert(connectionString, dataTable, destinationTableName, batchSize);
} public static void Insert(string connectionString, DataTable dataTable, string destinationTableName, int batchSize = )
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
if (connection.State != ConnectionState.Open)
{
connection.Open();
}
using (SqlTransaction transaction = connection.BeginTransaction())
{
using (SqlBulkCopy bulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.Default, transaction))
{
bulkCopy.BatchSize = batchSize;
bulkCopy.DestinationTableName = destinationTableName;
try
{
bulkCopy.WriteToServer(dataTable);
transaction.Commit();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
transaction.Rollback();
}
}
}
}
}

批量添加测试代码

public static void Insert()
{
List<Product> products = new List<Product>();
for (int i = ; i < ; i++)
{
Product product = new Product
{
Id = Guid.NewGuid().ToString(),
Name = $"商品{i}",
Price = (decimal)i
};
products.Add(product);
}
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
Insert(SqLiteHelper.SqlServerConnection, products, "Product");
stopwatch.Stop();
Console.WriteLine("耗时:" + stopwatch.ElapsedMilliseconds);
}

批量更新

public static void Update<T>(string connectionString, List<T> list, string destinationTableName)
{
var dt = ConvertToDataTable(list);
using (SqlConnection connection = new SqlConnection(connectionString))
{
if (connection.State != ConnectionState.Open)
{
connection.Open();
}
using (SqlTransaction transaction = connection.BeginTransaction())
{
using (SqlCommand command = new SqlCommand(string.Empty, connection))
{
try
{
command.Transaction = transaction;
command.CommandText = "CREATE TABLE #TmpTable(Id varchar(36),Name varchar(255),Price decimal(18,4))";
command.ExecuteNonQuery();
using (SqlBulkCopy bulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.Default, transaction))
{
bulkCopy.BulkCopyTimeout = ;
bulkCopy.DestinationTableName = "#TmpTable";
bulkCopy.WriteToServer(dt);
bulkCopy.Close();
}
command.CommandTimeout = ;
command.CommandText = "UPDATE T SET T.Name =Temp.Name FROM " + destinationTableName + " T INNER JOIN #TmpTable Temp ON T.Id=Temp.Id; DROP TABLE #TmpTable;";
command.ExecuteNonQuery();
transaction.Commit();
}
catch (Exception)
{
transaction.Rollback();
}
}
}
}
}

批量更新测试代码

        public static List<string> GetList()
{
List<string> list = new List<string>();
using (SqlConnection conn = new SqlConnection(SqLiteHelper.SqlServerConnection))
{
using (SqlCommand command = new SqlCommand("SELECT TOP 5000 Id FROM Product", conn))
{
conn.Open();
var data = command.ExecuteReader();
while (data.Read())
{
list.Add(data["Id"].ToString());
}
}
} return list;
} public static void Update()
{
var list = GetList();
List<Product> products = new List<Product>();
for (int i = ; i < list.Count; i++)
{
Product product = new Product
{
Id = list[i],
Name = $"默认{i}",
Price = (decimal)i *
};
products.Add(product);
}
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
Update(SqLiteHelper.SqlServerConnection, products, "Product");
stopwatch.Stop();
Console.WriteLine("耗时:" + stopwatch.ElapsedMilliseconds);
}

List转DataTable

 public static DataTable ConvertToDataTable<T>(IList<T> data)
{
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T));
DataTable table = new DataTable();
foreach (PropertyDescriptor prop in properties)
{
table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
}
foreach (T item in data)
{
DataRow row = table.NewRow();
foreach (PropertyDescriptor prop in properties)
{
row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
}
table.Rows.Add(row);
}
return table;
}

实体类

 public class Product
{
public string Id { get; set; } public string Name { get; set; } public decimal Price { get; set; }
}

链接字符串配置

 public class SqLiteHelper
{
public const string SqlServerConnection = "Data Source=IP;Initial Catalog=库名;uid=帐号;pwd=密码;MultipleActiveResultSets=True";
}

测试了一下 添加10W 差不多 10S左右

补充一个 多表操作

public static void Inserts(string connectionString, Dictionary<string, DataTable> dataTables, int batchSize = )
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
if (connection.State != ConnectionState.Open)
{
connection.Open();
}
using (SqlTransaction transaction = connection.BeginTransaction())
{
try
{
foreach (var item in dataTables)
{
using (SqlBulkCopy bulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.Default, transaction))
{
bulkCopy.BatchSize = batchSize;
bulkCopy.DestinationTableName = item.Key;
bulkCopy.WriteToServer(item.Value);
}
}
transaction.Commit();
}
catch (Exception ex)
{ Console.WriteLine(ex.Message);
transaction.Rollback();
}
}
}
}

测试代码

public static void Inserts()
{
const int count = ;
List<Order> orders = new List<Order>();
List<Product> products = new List<Product>();
for (var i = ; i < count; i++)
{
Product product = new Product
{
Id = Guid.NewGuid().ToString(),
Name = $"商品{i}",
Price = i * 0.8M
};
products.Add(product);
Order order = new Order
{
Id = Guid.NewGuid().ToString(),
ProductId = product.Id,
Remake = "suggestions",
Status =
};
orders.Add(order);
}
var productsDataTable = Batch.ConvertToDataTable(products);
var ordersDataTable = Batch.ConvertToDataTable(orders);
Dictionary<string, DataTable> dataTables = new Dictionary<string, DataTable>
{ { "Product", productsDataTable},
{ "Orders",ordersDataTable}
}; Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
Inserts(SqLiteHelper.SqlServerConnection, dataTables);
stopwatch.Stop();
Console.WriteLine("耗时:" + stopwatch.ElapsedMilliseconds);
}

新增订单实体对象

    public class Order
{
public string Id { get; set; } public string ProductId { get; set; } public int Status { get; set; } public string Remake { get; set; }
}

Order表结构

DROP TABLE [dbo].[Orders]
GO
CREATE TABLE [dbo].[Orders] (
[Id] varchar(36) NOT NULL ,
[ProductId] varchar(36) NOT NULL ,
[Status] int NOT NULL ,
[Remake] varchar(255) NOT NULL
) GO ALTER TABLE [dbo].[Orders] ADD PRIMARY KEY ([Id])
GO

批量删除也贴一个吧

  public void BatchDelete<T>(List<T> idList)
{
var type = typeof(T);
var id = GetProperties(type);
var innerJoin = $"a.{id}=b.{id}";
var tempTableName = $"#TmpTable{type.Name}";
var dataTableName = BulkCopyRepositoryExtension.GetTableName(type);
var sqlConnection = (SqlConnection)_unit.Connection;
var sqlTransaction = (SqlTransaction)_unit.Transaction;
var sqlCommand = (SqlCommand)_unit.Command;
sqlCommand.CommandText = $"SELECT * INTO {tempTableName} FROM {dataTableName} WHERE 1 = 2";
sqlCommand.ExecuteNonQuery();
using (SqlBulkCopy bulkCopy = new SqlBulkCopy(sqlConnection, SqlBulkCopyOptions.Default, sqlTransaction))
{
bulkCopy.DestinationTableName = tempTableName;
using (var reader = new ObjectReader(type, idList, BulkCopyRepositoryExtension.GetFields(type)))
{
bulkCopy.WriteToServer(reader);
}
}
sqlCommand.CommandText = $"DELETE a FROM {dataTableName} AS a INNER JOIN {tempTableName} AS b ON {innerJoin}; DROP TABLE {tempTableName};";
sqlCommand.ExecuteNonQuery();

批量删除关键代码已贴上  如需全部代码 QQ群 4816230869

为了满足关注粉丝的要求贴上说明

1、SqlBulkCopy类的构造方法

其中: conn表示一个SqlConnection对象

connStr表示数据库连接字符串

  1. SqlBulkCopy(conn)
  2. SqlBulkCopy(connStr)
  3. SqlBulkCopy(connStr, SqlBulkCopyOptions copyOptions)
  4. SqlBulkCopy(conn, SqlBulkCopyOptions copyOptions, SqlTransaction externalTransaction)

其中还有几个陌生的对象:SqlBulkCopyOptions 和 SqlTransaction

1.1、SqlBulkCopyOptions类

这个类是一个枚举类型:

对象 备注
Default 0  
KeepIdentity 1 保留源标识值。
如果未指定,则由目标分配标识值。
CheckConstraints 2 在插入数据的同时检查约束。
默认情况下,不检查约束。
TableLock 4 在批量复制操作期间获取批量更新锁。
如果未指定,则使用行锁。
KeepNulls 8 保留目标表中的空值,而不管默认值的设置如何。
如果未指定,则空值将由默认值替换(如果适用)
FireTriggers 16 指定后,会导致服务器为插入到数据库中的行激发插入触发器。
UseInternalTransaction 32

如果已指定,则每一批批量复制操作将在事务中进行。

如果指示了此选项,并且为构造函数提供了 System.Data.SqlClient.SqlTransaction对象,则发生 System.ArgumentException(参数异常)。因为两个事务冲突了。

1.2、SqlTransaction类

这个类是事务类,是个密封类,实现了DbTransaction抽象类

2、SqlBulkCopy类的常用属性

属性名 功能 备注
BatchSize 设置或获取每达到多少行就更新到服务器(也就是目标表) 值为int,
BulkCopyTimeout 设置或获取超时时间 默认30秒,如果设置成0,将无限制等待,
值为int,单位为秒
DestinationTableName 设置或获取服务器上的目标表的名称 也就是批量更新的目标表,
值为String类型
EnableStreaming 设置或获取是否支持传输 IDataReader 对象的数据 true为支持,
值为bool类型
NotifyAfter 设置或获取在生成通知事件之前要处理的行数 默认为0,
值为int类型,
ColumnMappings 获取列映射定义数据源中的列和目标表中的列之间的映射关系 返回值为SqlBulkCopyColumnMappingCollection

2.1、表中的SqlBulkCopyColumnMappingCollection类型是一个映射集合类,是目标表的列和源表的列的映射关系的集合。

这个类是一个密封类,不能被继承,实现了一个CollectionBase抽象类。

SqlBulkCopyColumnMappingCollection没有提供构造方法,我们也不需要去newat的对象,主要是使用它的几个重载的Add()方法

Add()有五个重载的方法:

  • SqlBulkCopyColumnMapping Add(SqlBulkCopyColumnMapping bulkCopyColumnMapping);
  • SqlBulkCopyColumnMapping Add(string sourceColumn, string destinationColumn);
  • SqlBulkCopyColumnMapping Add(int sourceColumnIndex, string destinationColumn);
  • SqlBulkCopyColumnMapping Add(string sourceColumn, int destinationColumnIndex);
  • SqlBulkCopyColumnMapping Add(int sourceColumnIndex, int destinationColumnIndex);

其中四个方法是类似的,都是对应的列名或者列的位置。

第一个方法是添加一个已经构建好的SqlBulkCopyColumnMapping对象,

他也有集合常用的方法:

方法名 功能 备注
Clear(); 清除集合中的映射关系  
Contains(SqlBulkCopyColumnMapping value); 判断是否包含指定映射关系  
IndexOf(SqlBulkCopyColumnMapping value); 返回指定映射关系的位置  
Remove(SqlBulkCopyColumnMapping value); 移除指定映射关系  
RemoveAt(int index); 移除指定位置的映射关系  
Insert(int index, SqlBulkCopyColumnMapping value); 在指定位置插入映射关系  
CopyTo(SqlBulkCopyColumnMapping[] array, int index); 从指定位置开始将映射关系复制到指定数组中 index指定的集合中的位置,
而不是数组中的角标

3、SqlBulkCopy类的常用方法

  • WriteToServer,这个方法重载了四次,功能是将数据写到目的表中。
WriteToServer(DataRow[] rows); 将 DataRow 数组所有元素写到目标表中
WriteToServer(DataTable table); 将 DataTable 所有行写到目标表中
WriteToServer(IDataReader reader); 将指定的 IDataReader 对象中的数据写到目标表中
WriteToServer(DataTable table, DataRowState rowState); 将 DataTable 中指定状态的所有行写到目标表中

【上表中的 DataRowState 状态行可以参考这篇博客DataTable的AcceptChanges()方法和DataRow的RowState属性

ado.net 批量添加 更新 删除的更多相关文章

  1. PHP中Cookie的使用---添加/更新/删除/获取Cookie 及 自动填写该用户的用户名和密码和判断是否第一次登陆

    PHP中Cookie的使用---添加/更新/删除/获取Cookie 及 自动填写该用户的用户名和密码和判断是否第一次登陆  什么是cookie 服务器在客户端保存用户的信息,比如登录名,密码等 这些数 ...

  2. Windows批量添加和删除IP

    随着天气变冷了,好多小伙伴都开始变懒了,都想用最快的方式完成任务 下面给大家介绍一下Windows批量添加和删除IP的办法 (1)批量添加IP 直接在CMD下边运行下边命令. for /l %i in ...

  3. SqlServer——批量操作(批量添加,删除)

    批量添加数据: 一条insert语句批量插入多条记录 常见的insert语句,向数据库中,一条语句只能插入一条数据: insert into persons (id_p, lastname , fir ...

  4. react.js 之 批量添加与删除功能

    最近做的CMS需要用到批量添加图片的功能:在添加文件的容器盒子内,有两个内容,分别是:添加按钮与被添加的选择文件组件. 结构分析: 被添加的组件,我们称为:UploadQiNiuFiles(七牛文件上 ...

  5. EF 批量 添加 修改 删除

    1批量添加    db.T_Investigator.AddRange(list) 2批量删除    db.T_Investigator.RemoveRange(list) 3批量修改   for 循 ...

  6. EF批量添加,删除,修改的扩展

    在EF各版本中,没有相应批量的添加,删除,修改,在用ORM 处理数据时直有个尴尬.在网上,也接到了很多网友的询问这方面的情况,特此今天把这方面的相关扩展分享一下,(这里只做批量删除的例子,添加和修改的 ...

  7. ADO.NET- 中批量添加数据的几种实现方法比较

    在.Net中经常会遇到批量添加数据,如将Excel中的数据导入数据库,直接在DataGridView控件中添加数据再保存到数据库等等. 方法一:一条一条循环添加 通常我们的第一反应是采用for或for ...

  8. MYSQL-JDBC批量新增-更新-删除

    目录 1 概述 2 开启MYSQL服务端日志 3 深入MYSQL/JDBC批量插入 3.1 从一个例子出发 3.2 JDBC的批量插入操作 3.3 两个常被忽略的问题 3.5 误区 4 MYSQL/J ...

  9. hive 批量添加,删除分区

    一.批量添加分区:   use bigdata; alter table siebel_member add if not exists partition(dt='20180401') locati ...

随机推荐

  1. Brocade SAN交换机常用命令

    Brocade SAN交换机常用命令 使用电脑连接Brocade SAN交换机常用命令 使用电脑连接管理网口,默认IP地址为:10.77.77.77,掩码:255.255.255.0 默认用户名:ad ...

  2. 我了解到的新知识之---Cylance Protect是干吗的?

    每家企业都会采购适合自己的杀毒软件来保护企业内的电脑处在安全的状态下,我所在的公司目前在用的是来自美国的初创企业的产品Cylance Protect.,目前这家公司已经在2018年11月份被黑莓公司收 ...

  3. 51单片机和STM32单片机区别在那里

    ​大部分朋友可能都知道51单片机和stm32单片机也知道一般入门会先学习51单片机在学习stm32单片机会简单一些,但是对于51单片机和stm32单片机的具体区别却不知道了,有些人觉得没必要,但是我个 ...

  4. 大数据量下的集合过滤—Bloom Filter

    算法背景 如果想判断一个元素是不是在一个集合里,一般想到的是将集合中所有元素保存起来,然后通过比较确定.链表.树.散列表(又叫哈希表,Hash table)等等数据结构都是这种思路,存储位置要么是磁盘 ...

  5. 前端paging分页,前端设置每页多少条和当前页面的索引,传给后端,数据显示出来

    1.首先引入jquery 2.在引入paging.css和paging.js  这2个我存在百度云上: 链接:https://pan.baidu.com/s/1SPxlBkkx-pNAtLuRLifE ...

  6. 使用js对WGS-84 ,GCJ-02与BD-09的坐标进行转换

    获取到经纬度在用百度地图进行定位时,却发现行驶轨迹的路线定到海里面去了.从网上查阅,知道此方法. 出处:https://www.jianshu.com/p/53f00ba897f7 一.在进行地图开发 ...

  7. Python Async/Await入门指南

    转自:https://zhuanlan.zhihu.com/p/27258289 本文将会讲述Python 3.5之后出现的async/await的使用方法,以及它们的一些使用目的,如果错误,欢迎指正 ...

  8. (已解决)jdk安装 系统找不到文件C:\ProgramData\Oracle\Java\javapath\java.exe

    jdk安装好之后,也配置好了环境变量,打开cmd输入javac可以跳出相关信息,可是输入java却一直提示:系统找不到文件C:\ProgramData\Oracle\Java\javapath\jav ...

  9. Java 五大原则

    1.单一职责 不论是在设计类,接口还是方法,单一职责都会处处体现,单一职责的定义:我们把职责定义为系统变化的原因.所有在定义类,接口,方法的时候.定义完以后再去想一想是不能多于一个的动机去改变这个类, ...

  10. Jmeter对jar包的调用赋值

    一.前言 在我们测试接口的过程中,可能有时需要用到第三方jar包来生成一些测试数据(如有时需要对参数的输入值使用第三方jar包进行加密操作),涉及到这种的情况,普遍做法是:手动调用jar包获得需要的值 ...