Получение 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);
}