我正在使用SqlBulkCopy
针对两个具有不同列集的SQL Server 2008(将一些数据从prod
服务器移动到dev
)。所以想要跳过一些尚未存在/尚未删除的列。
我该怎么做? ColumnMappings
的一些技巧?
修改
我接下来会这样做:
DataTable table = new DataTable();
using (var adapter = new SqlDataAdapter(sourceCommand))
{
adapter.Fill(table);
}
table.Columns
.OfType<DataColumn>()
.ForEach(c => bulk.ColumnMappings.Add(
new SqlBulkCopyColumnMapping(c.ColumnName, c.ColumnName)));
bulk.WriteToServer(table)
并获得:
给定的ColumnMapping与源或目标中的任何列都不匹配。
答案 0 :(得分:16)
DataTable table = new DataTable();
using (var adapter = new SqlDataAdapter(sourceCommand))
{
adapter.Fill(table);
}
using (SqlBulkCopy bulk = new SqlBulkCopy(targetConnection, SqlBulkCopyOptions.KeepIdentity, null) { DestinationTableName = tableName })
{
foreach (string columnName in GetMapping(stringSource, stringTarget, tableName))
{
bulk.ColumnMappings.Add(new SqlBulkCopyColumnMapping(columnName, columnName));
}
targetConnection.Open();
bulk.WriteToServer(table);
}
private static IEnumerable<string> GetMapping(string stringSource, string stringTarget, string tableName)
{
return Enumerable.Intersect(
GetSchema(stringSource, tableName),
GetSchema(stringTarget, tableName),
StringComparer.Ordinal); // or StringComparer.OrdinalIgnoreCase
}
private static IEnumerable<string> GetSchema(string connectionString, string tableName)
{
using (SqlConnection connection = new SqlConnection(connectionString))
using (SqlCommand command = connection.CreateCommand())
{
command.CommandText = "sp_Columns";
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add("@table_name", SqlDbType.NVarChar, 384).Value = tableName;
connection.Open();
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
yield return (string)reader["column_name"];
}
}
}
}
答案 1 :(得分:10)
使用SqlBulkCopyColumnMapping时,只会复制为其创建映射的列。
如果没有为列创建映射,则复制过程将忽略该映射。
您可以在演示代码here中看到这一点 - AdventureWorks演示数据库中的示例源表包含的列数多于映射或复制的列数。
修改强>
如果没有关于数据库模式的更多信息,很难确定,但是猜测问题出现在这个声明中:
new SqlBulkCopyColumnMapping(c.ColumnName, c.ColumnName)
根据您的描述,听起来并非源表中的所有列都存在于目标表中。您需要在SqlBulkCopyColumnMapping
构造循环中使用过滤器来跳过目标中不存在的任何列。
我的C#不够好,不能给出一个我相信会有效的例子,但在伪代码中它会是
foreach column c in sourcetable
{
if c.ColumnName exists in destination_table.columns
{
new SqlBulkCopyColumnMapping(c.ColumnName, c.ColumnName)
}
}
(我确信可以将其转换为lambda表达式)
请注意,在列名匹配但数据类型不兼容的情况下,这不是特别健壮。
答案 2 :(得分:3)
Ed Harper,这就是没有伪代码的样子 (在本例中,从DataTable dt(完全定义)到db中的现有表:
using (SqlBulkCopy bulkCopy = new SqlBulkCopy(connectionString))
{
bulkCopy.DestinationTableName = "dbo.DepartmentsItems";
// Write from the source to the destination.
foreach (DataColumn c in dt.Columns)
{
bulkCopy.ColumnMappings.Add(c.ColumnName, c.ColumnName);
}
bulkCopy.WriteToServer(dt);
return dt.Rows.Count;
}
答案 3 :(得分:1)
试试这个:SqlBulkCopyColumnMapping Class
希望您正在寻找相同的