介绍:
在软件开发中,把数据从一个地方复制到另一个地方是一个普遍的应用。 在很多不同的场合都会执行这个操作,包括旧系统到新系统的移植,从不同的数据库备份数据和收集数据。 ASP.NET 2.0有一个SqlBulkCopy类,它可以帮助你从不同的数据源复制数据到SQL SERVER数据库。 本文中我将示范SqlBulkCopy类的不同应用。
数据库设计:
这个数据库的设计还是蛮简单的,它基于Northwind数据库的Products表。另外我还在Northwind数据库中创建了3个表。 详情可以看一下下面的数据库关系图。
Products_Archive 和Products_Latest有与Products表相同的结构,而Products_TopSelling表则与它们不同。 稍后我将在本文解释Products_TopSelling表的用途。
Products_Archive表包含770,000行。 你不用管这些数据是如何得到的,你只需要考虑如何把所有这些数据复制到Products_Latest表里。
从Products_Archive表 复制数据到 Products_Latest表:
SqlBulkCopy 包含一个方法 WriteToServer,它用来从数据的源复制数据到数据的目的地。 WriteToServer方法可以处理的数据类型有DataRow[]数组,DataTable 和 DataReader。 你可以根据不同的情形使用不同的数据类型,但是更多时候选择DataReader是一个比较好的主意。 这是因为DataReader是一个只向前的、只读的数据流,它不会保存数据,所以要比DataTable 和 DataRows[]都要快。 下面的代码的作用是把数据从源表复制到目的表。
private
static
void PerformBulkCopy()
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
{
string connectionString =
@"Server=localhost;Database=Northwind;Trusted_Connection=true";
// 源
using (SqlConnection sourceConnection =
new SqlConnection(connectionString))
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
{
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
SqlCommand myCommand =
new SqlCommand(
"SELECT * FROM Products_Archive", sourceConnection);
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
sourceConnection.Open();
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
SqlDataReader reader = myCommand.ExecuteReader();
// 目的
using (SqlConnection destinationConnection =
new SqlConnection(connectionString))
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
{
// 打开连接
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
destinationConnection.Open();
using (SqlBulkCopy bulkCopy =
new SqlBulkCopy(destinationConnection.ConnectionString))
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
{
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
bulkCopy.BatchSize = 500;
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
bulkCopy.NotifyAfter = 1000;
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
bulkCopy.SqlRowsCopied +=
new SqlRowsCopiedEventHandler(bulkCopy_SqlRowsCopied);
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
bulkCopy.DestinationTableName =
"Products_Latest";
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
bulkCopy.WriteToServer(reader);
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
}
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
}
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
reader.Close();
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
}
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
}
这里有一对需要提及的知识点。 首先,我使用DataReader来从数据库的表中读取数据。 Products_Latest是目的表,因为数据要从Products_Archive表复制到Products_Latest表。 bulkCopy对象提供了一个SqlRowCopied事件,在每次处理完NotifyAfter属性指定的行数时发生。 本例中的意思就是每处理完1000行就触发一次该事件,因为NotifyAfter被设置成了1000
BatchSize属性是非常重要的,程序性能如何主要就依靠着它。 BatchSize的意思就是同每一批次中的行数,在每一批次结束时,就将该批次中的行发送到数据库。 我将BatchSize设置成了500,其意思就是reader每读出500行就将他们发送到数据库从而执行批量复制的操作。 BatchSize的默认值是“1”,其意思就是把每一行作为一个批次发送到数据库。
设置不同的BatchSize在性能上将给你带来不同的结果。 你应该根据你的需求进行测试,来决定BatchSize的大小。
在不同的映射表之间复制数据
在上面的例子中两个表具有相同的结构。 有时,你需要在具有不同结构的表之间复制数据。 假如你要从Products_Archive表中把所有的产品名称及其数量复制到Products_TopSelling表里。 这两个表有着不同的字段名,具体可以看一下上面的“数据库设计”一节下的。
private
static
void PerformBulkCopyDifferentSchema()
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
{
string connectionString =
@"Server=localhost;Database=Northwind;Trusted_Connection=true";
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
DataTable sourceData =
new DataTable();
// 源
using (SqlConnection sourceConnection =
new SqlConnection(connectionString))
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
{
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
SqlCommand myCommand =
new SqlCommand(
"SELECT TOP 5 * FROM Products_Archive", sourceConnection);
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
sourceConnection.Open();
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
SqlDataReader reader = myCommand.ExecuteReader();
// 目的
using (SqlConnection destinationConnection =
new SqlConnection(connectionString))
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
{
// 打开连接
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
destinationConnection.Open();
using (SqlBulkCopy bulkCopy =
new SqlBulkCopy(destinationConnection.ConnectionString))
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
{
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
bulkCopy.ColumnMappings.Add(
"ProductID",
"ProductID");
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
bulkCopy.ColumnMappings.Add(
"ProductName",
"Name");
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
bulkCopy.ColumnMappings.Add(
"QuantityPerUnit",
"Quantity");
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
bulkCopy.DestinationTableName =
"Products_TopSelling";
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
bulkCopy.WriteToServer(reader);
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
}
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
}
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
reader.Close();
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
}
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
}
ColumnMappings集合用于映射源表和目的表之间的列。
从XML文件复制数据到数据库的表中
数据源并不局限于数据库的表,你也可以使用XML文件做数据源。 这里有一个非常简单的使用XML文件做数据源进行批量复制操作的例子。
(Products.xml)
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
<?xml version=
"1.0" encoding=
"utf-8" ?>
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
<Products>
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
<Product productID=
"1" productName=
"Chai" />
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
<Product productID=
"2" productName=
"Football" />
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
<Product productID=
"3" productName=
"Soap" />
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
<Product productID=
"4" productName=
"Green Tea" />
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
</Products>
private
static
void PerformBulkCopyXMLDataSource()
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
{
string connectionString =
@"Server=localhost;Database=Northwind;Trusted_Connection=true";
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
DataSet ds =
new DataSet();
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
DataTable sourceData =
new DataTable();
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
ds.ReadXml(
@"C:Products.xml");
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
sourceData = ds.Tables[0];
// 目的
using (SqlConnection destinationConnection =
new SqlConnection(connectionString))
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
{
// 打开连接
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
destinationConnection.Open();
using (SqlBulkCopy bulkCopy =
new SqlBulkCopy(destinationConnection.ConnectionString))
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
{
// 列映射
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
bulkCopy.ColumnMappings.Add(
"productID",
"ProductID");
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
bulkCopy.ColumnMappings.Add(
"productName",
"Name");
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
bulkCopy.DestinationTableName =
"Products_TopSelling";
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
bulkCopy.WriteToServer(sourceData);
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
}
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
}
![InBlock.gif](http://zhoufoxcn.blog.51cto.com/images/editer/InBlock.gif?x-oss-process=image/resize,w_1400/format,webp)
}
首先把XML文件读进DataTable,然后再使用SqlBulkCopy类的WriteToServer方法。 因为目的表示是Products_TopSelling,所以我们必须执行列映射。
结论
本文中我示范了如何使用.NET 2.0引入的SqlBulkCopy类。 SqlBulkCopy类可以非常简单的把数据从一个数据源复制到SQL SERVER数据库。
本文转自周金桥51CTO博客,原文链接:http://blog.51cto.com/zhoufoxcn/166052 ,如需转载请自行联系原作者