在SqlBulkCopy中跳过一些列

c# columnmappings sqlbulkcopy sql-server sql-server-2008

我正在使用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与源或目标中的任何列都不匹配。

一般承认的答案

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"];
            }
        }
    }
}

热门答案

使用SqlBulkCopyColumnMapping时,仅复制为其创建映射的列。

如果不为列创建映射,则复制过程将忽略该映射。

您可以在此处的演示代码中看到这一点 - 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表达式)

请注意,在列名匹配但数据类型不兼容的情况下,这不是特别强大。



许可下: CC-BY-SA with attribution
不隶属于 Stack Overflow
这个KB合法吗? 是的,了解原因
许可下: CC-BY-SA with attribution
不隶属于 Stack Overflow
这个KB合法吗? 是的,了解原因