Пропустить некоторые столбцы в SqlBulkCopy - PullRequest
9 голосов
/ 24 сентября 2010

Я использую 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 не совпадает ни с одним столбцом в источнике или месте назначения.

Ответы [ 4 ]

16 голосов
/ 24 сентября 2010
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"];
            }
        }
    }
}
10 голосов
/ 24 сентября 2010

Когда используется SqlBulkCopyColumnMapping, будут скопированы только столбцы, для которых созданы сопоставления.

Если вы не создадите отображение для столбца, оно будет проигнорировано процессом копирования.

Это можно увидеть в демонстрационном коде здесь - пример исходной таблицы в демонстрационной базе данных AdventureWorks содержит больше столбцов, чем сопоставлено или скопировано.

EDIT

Трудно быть уверенным без дополнительной информации о схеме базы данных, но, по-видимому, проблема заключается в следующем утверждении:

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)
    }
}

(я уверен, что можно преобразовать это в лямбда-выражение)

Обратите внимание, что это не особенно надежно в сценарии, где имена столбцов совпадают, но типы данных несовместимы.

3 голосов
/ 18 сентября 2017

Эд Харпер, вот как это выглядит без псевдокода (в данном случае от DataTable dt (полностью определено) до существующей таблицы в базе данных:

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;
}
1 голос
/ 24 сентября 2010

попробуйте: SqlBulkCopyColumnMapping Class

Надеюсь, вы ищете то же самое

...