我正在将一些基于存储过程的报告例程转换为在C#中运行。一般的想法是使用C#/ .NET Framework的所有奇迹,然后将结果反馈到数据库中。除了我昨天遇到的一个问题并且今天已经解决了,所以一切都在游动。
要进行导入,我是以编程方式创建DataTable并使用SqlBulkCopy将结果移动到服务器。
e.g。
DataTable detail = new DataTable();
detail.Columns.Add(new DataColumn("Stock", Type.GetType("System.Decimal")));
detail.Columns.Add(new DataColumn("Receipts", Type.GetType("System.Decimal")));
detail.Columns.Add(new DataColumn("Orders", Type.GetType("System.Decimal")));
导入表按以下顺序包含字段。
...
Stock decimal(18,4),
Orders decimal(18,4),
Receipts decimal(18,4)
...
基本上,收据的价值是进入订单,反之亦然。
显然,这是因为SqlBulkCopy似乎没有尊重我告诉它填充的列名 - 它只是按顺序位置。
这对我来说是一个问题,因为我们使用Redgate的SQL Compare。将更改从一个数据库推送到另一个数据库时,不一定保持列的序号位置。 (例如,如果您将新列作为第三个序号字段插入,则SQL Compare将在同步时将其附加到表中,使其成为最后一列)。
这严重困扰我的解决方案。现在,这些只是“导入”表,因此如果需要,我可以删除并重新创建它们作为任意迁移脚本的一部分,序数位置保持不变。我宁愿不这样做。
有没有办法强制SqlBulkCopy遵守你告诉它填充的列名?
答案 0 :(得分:18)
这是解决此问题的解决方案'。
默认是按顺序/位置进行映射。
在我的情况下,我是从包含随机顺序列的电子表格加载的。这是一个快速解决方法(表格是我的DataTable,它是序数顺序',而bulkCopy是SqLBulkCopy对象)
foreach (DataColumn col in table.Columns)
{
bulkCopy.ColumnMappings.Add(col.ColumnName, col.ColumnName);
}
正如您所看到的,即使名称是IDENTICAL,我也只是强迫它按名称重新排序。
答案 1 :(得分:16)
来自http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlbulkcopy.columnmappings.aspx:
但是,如果列数不同,或者序数位置不同 一致,您必须使用ColumnMappings来确保数据 复制到正确的列。
有关示例代码,请参阅http://www.sqlteam.com/article/use-sqlbulkcopy-to-quickly-load-data-from-your-client-to-sql-server
上的“映射列”答案 2 :(得分:1)
项目选项中的SQL比较强制列顺序中有一个选项。这将生成一个将重新排序列的脚本。我可能错了,但我认为此操作可能需要重建表,因此请谨慎使用,因为这可能会影响性能。但是,该脚本将保留表数据。
答案 3 :(得分:0)
有一些重载可以让您指定序号位置,或者要映射到目标列的源列名称。
结帐SqlBulkCopyColumnMappingCollection.Add并设置SqlBulkCopy.ColumnMappings
属性。
答案 4 :(得分:0)
我可能会遗漏一些东西,但为什么不能改变列的顺序?我通常不会手工构建DataTable
。我使用SqlDataAdapter
"select * from targetTable"
方法,使用DataTable
查询。所以我总是确定我的{{1}}适合目标表。
答案 5 :(得分:0)
Here's a Gist with an extension method for it。
示例:
bulkCopy
.WithColumnMappings(table.Columns)
.WriteToServer(table);
这将清除现有的列映射,然后为传入的每个列添加一个映射。
答案 6 :(得分:0)
一种在批量复制中实现列映射的简单方法,请确保您的数据表列名称与您要转储所有数据的表中的名称完全相同
using (SqlBulkCopy bulkcopy = new SqlBulkCopy(dc.ConnectionString))
{
bulkcopy.BulkCopyTimeout = 150;
// column mapping defined
dt.Columns.Cast<DataColumn>().ToList().ForEach(f =>
{
SqlBulkCopyColumnMapping bccm = new SqlBulkCopyColumnMapping();
bccm.DestinationColumn = f.ColumnName;
bccm.SourceColumn = f.ColumnName;
bulkcopy.ColumnMappings.Add(bccm);
});
// column mapping defined
bulkcopy.DestinationTableName = outputTable;
bulkcopy.WriteToServer(dt);
}