在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合法嗎? 是的,了解原因