пятница, 4 сентября 2009 г.

Синхронизация источников данных, c#

Уже не первый раз за свою практику сталкиваюсь с необходимостью синхронизации таблиц данных, которые хранятся различным образом. Ну, например, основная база данных храниться в СУБД (MS SQL Server, FireBird и т.д.), а некие наборы данных приходят в виде XML файлов.

И так, задача. Данные хранимые в СУБД должны соответсвовать тем данным, которые "пришли" в XML.
Таблица в СУБД имеет структутру Customer(int code, nvarchar name).
Как поступают входны данные, нам собственно и не важно.


Попытка №1
Конечно же, была очень плохой. Я делал 2 прохода по таблицам:
1 проход: перебор записей исходной таблицы, поиск в внешнем наборе.
2 проход: перебор записей внешнего набора, поиск в исходной таблице.
Очень медленно. Лишние переборы.

Попытка №2
Пообщавшись с мировой мудростью, дела пошли лучше.
Условие работы метода - наличие у данных PrimaryKey.
Сортируем исходную таблицу и внешний набор по значению PK (в нашем случае Customer.Code)

//Создаём два индекса для перебора записей
int iNew = 0;
int iCurrent = 0;

//В цикле выбираем 2 записи из таблицы. Нам конечно нужны только их PK.
int newId = (int)newCustomers.Rows[iNew]["Code"];
int currentId = (int)currentCustomers.Rows[iCurrent]["Code"];

//Сравниваем значения PK.
switch(newId.CompareTo(curId))
{
//add new
case -1:  
          Customer customer = new Customer();
           customer.Code = newCustomers.Rows[iNew]["Code"];
           customer.Name = newCustomers.Rows[iNew]["Name"];
           InsertCustomer(customer);
           iNew++;
           break;
//update
case 0:
           currentCustomers.Rows[iCurrent]["Name"] = newCustomers.Rows[iNew]["Name"];
           iNew++;
           iCur++;
           break;
//delete
case 1:
           DeleteCustomer(currentCustomers.Rows[iCurrent]);
           iCur++;
           break;
}
Количество циклов N = newCustomers.Rows U currentCustomers.Rows
Методы InsertCustomer, DeleteCustomer - методы реализующие логику добавления и удаления записей, соответственно.