Я столкнулся с проблемой при использовании DataAdapter, и я надеюсь, что кто-то может помочь. В основном я создаю систему, которая выглядит следующим образом:
- Данные считываются из источника данных (MS-Access, SQL Server или Excel), преобразуются в таблицы данных и вставляются в локальную базу данных SQL Server с помощью DataAdapters. Этот бит работает нормально. В таблице SQL-сервера есть PK, представляющий собой поле идентификации с включенным автоматическим приращением.
- Последующие загрузки данных считывают данные из источника и сравнивают их с тем, что у нас уже есть. Если запись отсутствует, то она добавляется (это работает нормально). Если запись отличается, ее необходимо обновить (это не работает).
- При загрузке разностных данных я создаю таблицу данных, которая считывает схему из целевой таблицы (сервер SQL) и гарантирует, что она имеет те же столбцы и т. д.
- PK в целевой таблице - это столбец 0, поэтому, когда запись вставляется, устанавливаются все значения из столбца 1 и далее (как уже упоминалось, это работает отлично). Я не меняю статус строки для элементов, которые добавляю. PK в таблице данных установлен правильно, и я могу это подтвердить.
- При обновлении данных я устанавливаю столбец 0 (столбец PK) в качестве значения записи, которую я обновляю, и устанавливаю все столбцы такими же, как исходные данные.
- Для обновленных записей я вызываю AcceptChanges и SetModified для строки, чтобы убедиться (как я думал), что приложение вызывает правильный метод.
- DataAdapter устанавливается с помощью SelectCommand и UpdateCommand с помощью построителя команд.
Когда я запускаю, я отслеживаю это с помощью профилировщика SQL и вижу, что команда вставки выполняется правильно, но команда обновления вообще не выполняется, что является сутью проблемы. Для справки таблица вставки будет выглядеть примерно так:
PK Value1 Value 2 Row State
== ====== ======= =========
124 Test1 Test 2 Added
123 Test3 Test4 Updated
Пара вещей, о которых нужно знать....
- Я проверил это, загрузив строку, которую нужно изменить, в таблицу данных, изменив некоторые поля столбца и запустив обновление, и это работает. Однако это нецелесообразно для моего решения, потому что данные ОГРОМНЫ > 1 Гб, поэтому я не могу просто загрузить их в таблицу данных без значительного снижения производительности. Что я делаю, так это создаю таблицу данных с максимальным количеством строк 500 и запускаю обновление. Тестирование во время начальной загрузки данных показало, что это наиболее эффективно с точки зрения использования памяти и производительности. Таблица данных очищается после запуска каждой партии.
У кого-нибудь есть идеи о том, где я ошибаюсь?
заранее спасибо
Андрей
==========Обновление==============
Ниже приведен код для создания строк вставки/обновления.
private static void AddNewRecordToDataTable(DbDataReader pReader, ref DataTable pUpdateDataTable)
{
// create a new row in the table
DataRow pUpdateRow = pUpdateDataTable.NewRow();
// loop through each item in the data reader - setting all the columns apart from the PK
for (int addCount = 0; addCount < pReader.FieldCount; addCount++)
{
pUpdateRow[addCount + 1] = pReader[addCount];
}
// add the row to the update table
pUpdateDataTable.Rows.Add(pUpdateRow);
}
private static void AddUpdateRecordToDataTable(DbDataReader pReader, int pKeyValue,
ref DataTable pUpdateDataTable)
{
DataRow pUpdateRow = pUpdateDataTable.NewRow();
// set the first column (PK) to the value passed in
pUpdateRow[0] = pKeyValue;
// loop for each row apart from the PK row
for (int addCount = 0; addCount < pReader.FieldCount; addCount++)
{
pUpdateRow[addCount + 1] = pReader[addCount];
}
// add the row to the table and then update it
pUpdateDataTable.Rows.Add(pUpdateRow);
pUpdateRow.AcceptChanges();
pUpdateRow.SetModified();
}
Для фактического обновления используется следующий код:
updateAdapter.Fill(UpdateTable);
updateAdapter.Update(UpdateTable);
UpdateTable.AcceptChanges();
Следующее используется для создания таблицы данных, чтобы убедиться, что она имеет те же поля/типы данных, что и исходные данные.
private static DataTable CreateDataTable(DbDataReader pReader)
{
DataTable schemaTable = pReader.GetSchemaTable();
DataTable resultTable = new DataTable(<tableName>); // edited out personal info
// loop for each row in the schema table
try
{
foreach (DataRow dataRow in schemaTable.Rows)
{
// create a new DataColumn object and set values depending
// on the current DataRows values
DataColumn dataColumn = new DataColumn();
dataColumn.ColumnName = dataRow["ColumnName"].ToString();
dataColumn.DataType = Type.GetType(dataRow["DataType"].ToString());
dataColumn.ReadOnly = (bool)dataRow["IsReadOnly"];
dataColumn.AutoIncrement = (bool)dataRow["IsAutoIncrement"];
dataColumn.Unique = (bool)dataRow["IsUnique"];
resultTable.Columns.Add(dataColumn);
}
}
catch (Exception ex)
{
message = "Unable to create data table " + ex.Message;
throw new Exception(message, ex);
}
return resultTable;
}