SqlBulkCopy вставка в таблицу с удостоверением

это мой сценарий: мне нужно импортировать огромные файлы в таблицу, поэтому я использовал sqlBulkCopy, потому что другие способы работают слишком медленно.

Это пример строки файла:

String1|String2|String3|String4

А вот структура таблицы:

Id (Identity,PK)|Column1|Column2|Column3|Column4

Я разделяю строку на '|', я создаю dataTable, куда помещаю каждый столбец таблицы (кроме Id), читающий информацию из файла конфигурации:

DataColumn dc;
foreach (Tables.BulkColumn bc in columns)
{
    dc = new DataColumn();
    dc.DataType = bc.ColumnValueType;
    dc.ColumnName = bc.Name;
    dc.Unique = false;
    actualDataTable.Columns.Add(dc);
}

Я загружаю данные из файла в dataTable (данные правильные), инициализирую SqlBulkCopy и writeToServer:

SqlBulkCopy sbc = new SqlBulkCopy(connectionString, SqlBulkCopyOptions.TableLock);
sbc.BulkCopyTimeout = 600;
sbc.WriteToServer(actualDataTable);

Но когда я смотрю в базу данных, это вставленная строка:

IncrementedId|String2|String3|String4

Он не вставляет значение Column1, похоже, он работает с индексом столбцов, но при инициализации dataColumns я явно задаю имя.

Вы знаете, как это решить? Идентификатор необходимо вставлять автоматически, правильно записывая другие значения.

(Я пытаюсь переместить Id в качестве последних столбцов, он работает правильно, но мне это решение не нравится)

ОБНОВЛЕНИЕ

Чтобы вставить данные из txt в таблицу, я читаю структуру таблицы из своей конфигурации, например

<table name="Table" file="D:\Progetti\TestArea\test\SqlBulkCopy\FP20150716003004.txt" incremental="false" active="true" identity="true">
      <field name="Column1" type="System.String" default="" key="false" allowsNull="true" length="50" />
 <!-- Other Fields --> ...

Все поля находятся в том же порядке, что и столбцы во входном файле. Я разделяю строки файла и помещаю данные в DataRow:

dr[actualIndexColumnName] = string.IsNullOrEmpty(splitted[columnIndex]) ? tab.Columns[columnIndex].DefaultValue : splitted[columnIndex];

Где splitted [columnIndex] - это фактическое входное значение, и когда все столбцы строки заполнены, я добавляю это значение в DataTable

dt.Rows.Add(dr);

person SamDroid    schedule 21.07.2015    source источник
comment
@stakx Я попытался установить SqlBulkCopyOptions.KeepIdentity = true, но это дает мне System.FormatException, потому что, похоже, он работает с использованием индексов (Id - int, column1 - nvarchar)   -  person SamDroid    schedule 21.07.2015
comment
Возможно, вам стоит остановиться и подумать, почему column1 равно nvarchar. Разве это не должно быть int, как в реальной схеме базы данных? Если да, означает ли это, что, возможно, вам нужно изменить код, который строит DataTable (т.е. добавить что-то вроде int.Parse после string.Split)?   -  person stakx - no longer contributing    schedule 21.07.2015
comment
Я отредактировал свой вопрос, изменив значения, вставленные в таблицу, чтобы уточнить, что столбцы, кроме Id, являются nvarchar   -  person SamDroid    schedule 21.07.2015
comment
1. Было бы полезно, если бы вы показали код, преобразующий введенные вами данные в DataTable. 2. Re: когда я смотрю в базу данных, это вставленная строка - как выглядит инструкция SELECT?   -  person stakx - no longer contributing    schedule 21.07.2015
comment
1. Я добавил код. 2. Выберите * из таблицы.   -  person SamDroid    schedule 21.07.2015
comment
Ваш SELECT * дает набор результатов с 4 столбцами, но ваш DataTable, по-видимому, имеет пять столбцов. Я понимаю, что в вашем DataTable есть столбец column1, но я предполагаю, что в вашей таблице базы данных нет такого же столбца. (Вы явно не описываете схему для своей таблицы базы данных.) Неудивительно, что она не вставляет значения из этого столбца в базу данных ...   -  person stakx - no longer contributing    schedule 21.07.2015


Ответы (2)


Вам не хватает карты столбцов для вашего SqlBulkCopy.

foreach (Tables.BulkColumn bc in columns)
{
   sbc.ColumnMapping.Add(bc.name);
}
person Remus Rusanu    schedule 21.07.2015
comment
Ваше решение работает, но не существует. Добавьте перегрузки, которые принимают только один параметр, поэтому я использовал перегрузку, принимающую columnName, columnPosition. - person SamDroid; 21.07.2015

Я решил свою проблему, добавив сопоставления в SqlBulkCopy следующим образом:

sbc.ColumnMappings.Clear();
int i = hasTableIdentity ? 1 : 0;
DataColumn dc;
foreach (Tables.BulkColumn bc in columns)
{
    dc = new DataColumn();
    dc.DataType = bc.ColumnValueType;
    dc.ColumnName = bc.Name;
    dc.Unique = false;
    sbc.ColumnMappings.Add(dc.ColumnName, i);
    actualDataTable.Columns.Add(dc);
    i++;
}
person SamDroid    schedule 22.07.2015