Получение SqlBulkCopy в честь имен столбцов

Я в процессе преобразования некоторых процедур отчетов на основе хранимых процедур для запуска в C#. Общая идея состоит в том, чтобы использовать все чудеса C#/.NET Framework, а затем взорвать результаты обратно в БД. Все идет гладко, за исключением одного вопроса, с которым я столкнулся вчера и решил сегодня.

чтобы выполнить импорт, я программно создаю DataTable и использую SqlBulkCopy для перемещения результатов в сервер.

например

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

это проблема для меня, поскольку мы используем SQL-сравнение Redgate. При нажатии изменений из одной базы данных в во-вторых, порядковое положение столбцов не обязательно поддерживается. (например, если вы вставляете новый столбец в качестве третьего порядкового поля, SQL Compare просто добавит его в таблицу при синхронизации, сделав его последним столбцом ).

это серьезно мешает моему решению. Теперь это только таблицы "импорта", поэтому, если нужно, я могу удалить и воссоздать их как часть любого сценария миграции с неповрежденными порядковыми позициями. Но я бы предпочел этого не делать.

есть ли способ заставить SqlBulkCopy, чтобы почтить имена столбцов, которые вы говорите ему заполнить?

7 ответов


от 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


вот решение, чтобы исправить эту "ошибку".

по умолчанию карты по порядку/должность.

в моем случае я загружался с листа с столбцами в случайном порядке. вот быстрое исправление (таблица-это мой DataTable, который "вне порядкового порядка", а bulkCopy-объект SqLBulkCopy)

foreach (DataColumn col in table.Columns)
{
    bulkCopy.ColumnMappings.Add(col.ColumnName, col.ColumnName);
}

Как вы можете видеть, я просто заставляю его переупорядочивать по имени, хотя имена идентичны.


в SQL Compare есть опция для принудительного порядка столбцов в параметрах проекта. Это создаст сценарий, который изменит порядок столбцов. Я могу ошибаться, но я думаю, что эта операция может потребовать перестроения таблицы, поэтому, пожалуйста, используйте с осторожностью, так как это может повлиять на производительность. Однако сценарий сохранит табличные данные.


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

проверить SqlBulkCopyColumnMappingCollection.Добавить и выберите SqlBulkCopy.ColumnMappings собственность.


возможно, я что-то пропустил, но почему вы не могли изменить порядок своих столбцов? Я обычно не строю свой DataTable вручную. Я использую метода fillschema метод SqlDataAdapter, С помощью "select * from targetTable" запрос. Поэтому я всегда уверен, что мой DataTableподходит для целевой таблицы.


вот суть с методом расширения для него.

пример:

bulkCopy
    .WithColumnMappings(table.Columns)
    .WriteToServer(table);

это очищает существующие сопоставления столбцов, а затем добавляет сопоставление для каждого переданного столбца.


простой способ реализации сопоставления столбцов в массовом копировании, убедитесь, что ваши имена столбцов datatable точно такие же, как в таблице, которую вы хотите сбросить все данные

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

}