您的位置:首页 > 数据库 > SQL

使用SqlBulkCopy类结合DataTable类快速完成对目标为SQLSERVER的数据交换

2009-12-04 14:29 701 查看
Microsoft SQL Server 提供一个称为 bcp 的流行的命令提示符实用工具,用于将数据从一个表移动到另一个表(表既可以在同一个服务器上,也可以在不同服务器上)。SqlBulkCopy 类允许编写提供类似功能的托管代码解决方案。还有其他将数据加载到 SQL Server 表的方法(例如 INSERT 语句),但相比之下 SqlBulkCopy 提供明显的性能优势。

使用 SqlBulkCopy 类只能向 SQL Server 表写入数据。但是,数据源不限于 SQL Server;可以使用任何数据源,只要数据可加载到 DataTable 实例或可使用 IDataReader 实例读取数据。

需求

需要完成一个多张表的数据交换,源数据库为oracle,目标为SqlServer。

源表分几个业务块,每一块有多张表,其中一张主表,其余若干子表。

主表主键和子表关联外键为字符型,据查是GUID字符串。

目标表业务模块基本一致。

主表主键和子表关联外键为数字型,据查是INT32类型。

分析

源和目标表的数据内容基本相似,最大区别为主键不一致,导致源表主键无法放入目标表,目标每条记录的主键必须重新赋值。

源表和目标表一些不一致的字段类型,比如date到varchar(8),varchar2(1)到bit等。

解决方法

由于SqlBulkCopy类能够批量插入数据到SqlServer,故采用该类作为数据交换。

源主到目标主表时,目标主键需要动态生成,同时目标子表的外键也需和主表主键对应。

思路如下:

先取得主表数据,然后生成DataTable类,附加一列动态生成目标主键列(轮询所有行,值从1到该DataTable的行数)。执行主表数据的插入。

依次取得子表所有数据DataTable,每张子表先增加一列,轮询所有行,按源外键关联主表DataTable找到动态生成的目标主键列,赋值给增加的那列。对新生成的子表DataTable依次插入目标子表。

源码

配置文件:
主表的标志,子表的标志,源表和目标表的各个字段的映射等都保存在配置文件中。

代码

private void buttonBegin_Click(object sender, EventArgs e)

{

if (String.IsNullOrEmpty(textBoxFile.Text.Trim()))

{

MessageBox.Show("请选择配置文件!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);

return;

}

try

{

XmlDocument doc = new XmlDocument();

doc.Load(textBoxFile.Text.Trim());

XmlNodeList mainTableNodes = doc.SelectNodes("configuration/TableMaps/MainTable");

DataTable dtSourceMain = new DataTable();

using (OracleConnection conn = new OracleConnection(SourceConnectString))

{

OracleCommand cmd = new OracleCommand();

cmd.Connection = conn;

cmd.CommandType = CommandType.Text;

StringBuilder sbSql = new StringBuilder();

String srcTableName;

String srcKey;

String destTableName;

String destKey;

if (mainTableNodes.Count < 1)

{

MessageBox.Show("配置文件不对,缺少主表!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);

return;

}

srcTableName = mainTableNodes[0].Attributes["SrcTableName"].Value;

srcKey = mainTableNodes[0].Attributes["SrcKey"].Value;

destTableName = mainTableNodes[0].Attributes["DestTableName"].Value;

DeleteTargetTable(destTableName);

destKey = mainTableNodes[0].Attributes["DestKey"].Value;

sbSql.Append("select ");

foreach (XmlNode node in mainTableNodes[0])

sbSql.AppendFormat("{0}, ", node.Attributes["SqlText"].Value);

//sbSql.Remove(sbSql.ToString().LastIndexOf(","), 1);

sbSql.Append(srcKey);

sbSql.AppendFormat(" from {0}", srcTableName);

cmd.CommandText = sbSql.ToString();

OracleDataAdapter adapter = new OracleDataAdapter(cmd);

adapter.Fill(dtSourceMain);

dtSourceMain.Columns.Add(destKey, Type.GetType("System.Int32"));

for (int i = 0; i < dtSourceMain.Rows.Count; i++)

{

dtSourceMain.Rows[i][destKey] = i + 1;

}

using (SqlBulkCopy sqlBC = new SqlBulkCopy(TargetConnectString, SqlBulkCopyOptions.UseInternalTransaction))

{

sqlBC.BatchSize = 1000;

sqlBC.BulkCopyTimeout = 300;

sqlBC.DestinationTableName = destTableName;

//主表数据插入

sqlBC.ColumnMappings.Add(destKey, destKey);

foreach (XmlNode childNode in mainTableNodes[0].ChildNodes)

{

sqlBC.ColumnMappings.Add(childNode.Attributes["SrcColumn"].Value, childNode.Attributes["DestColumn"].Value);

}

sqlBC.WriteToServer(dtSourceMain);

//准备子表数据

XmlNodeList subTableNodes = doc.SelectNodes("configuration/TableMaps/SubTable");

progressBar.Maximum = subTableNodes.Count;

this.progressBar.Value = 1;

this.progressBar.Step = 1;

this.progressBar.PerformStep();

String srcForeignKey;

String destForeignKey;

foreach (XmlNode node in subTableNodes)

{

this.progressBar.PerformStep();

DataTable dtSourceSub = new DataTable();

srcTableName = node.Attributes["SrcTableName"].Value;

srcForeignKey = node.Attributes["SrcForeignKey"].Value;

destTableName = node.Attributes["DestTableName"].Value;

DeleteTargetTable(destTableName);

destForeignKey = node.Attributes["DestForeignKey"].Value;

sqlBC.DestinationTableName = destTableName;

sqlBC.ColumnMappings.Clear();

sqlBC.ColumnMappings.Add(destForeignKey, destForeignKey);

sbSql = new StringBuilder();

sbSql.Append("select ");

foreach (XmlNode childnodes in node.ChildNodes)

{

sbSql.AppendFormat("{0}, ", childnodes.Attributes["SqlText"].Value);

sqlBC.ColumnMappings.Add(childnodes.Attributes["SrcColumn"].Value, childnodes.Attributes["DestColumn"].Value);

}

sbSql.Append(srcForeignKey);

sbSql.AppendFormat(" from {0}", srcTableName);

cmd.CommandText = sbSql.ToString();

adapter = new OracleDataAdapter(cmd);

adapter.Fill(dtSourceSub);

dtSourceSub.Columns.Add(destForeignKey, Type.GetType("System.Int32"));

for (int i = 0; i < dtSourceSub.Rows.Count; i++)

{

DataRow[] drs = dtSourceMain.Select(String.Format("{0}='{1}'", srcKey, dtSourceSub.Rows[i][srcForeignKey]));

if (drs.Length > 0)

dtSourceSub.Rows[i][destForeignKey] = drs[0][destKey];

}

sqlBC.WriteToServer(dtSourceSub);

}

}

}

MessageBox.Show("数据转换成功,请查看目标表数据", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);

progressBar.Value = 0;

}

catch (Exception ex)

{

MessageBox.Show(ex.Message, "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);

}

}

备注

使用SqlBulkCopy 类,配置映射时,目标表各个字段的名称必须和数据库中的字段名称保持大小写一致。

各个数据类型的转换的时候,必须在映射的DataTable已经转换好,最好是查询的SQL语句,已经转换好,相见配置文件。

插入的时候,目标表不能有重复主键,否则失败;每条记录的每个字段的实际值大小不能超过目标表,否则报错。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: