Сравнение двух наборов данных - PullRequest
0 голосов
/ 05 апреля 2011

У меня есть необходимость импортировать данные из Oracle в MySQL.Мне нужно обновить данные MySQL данными из Oracle.У меня есть настройки кода для получения данных из обоих ресурсов, но у меня возникает проблема выяснения наилучшего способа обновления информации.

Я пробовал DataSet.Merge, но на самом деле это не помечаетRowState правильно.Я надеялся использовать:

ds1 = GetMySQLData();
ds2 = GetOracleData();

ds1.Merge(ds2);

changesDataSet = myData.GetChanges(DataRowState.Modified);

RowState не изменяется.Я точно знаю, что он изменяет данные, поскольку я специально изменил что-то в своей тестовой базе данных на MySQL и увидел изменение после того, как вызвал слияние.

Есть ли известный способ (алгоритм), который я могуиспользовать для проверки наборов данных друг против друга и вставки, обновления, удаления записей?

1 Ответ

0 голосов
/ 05 апреля 2011

Первоначально я предложил вызвать перегрузку Merge () с preserveChanges = true, но это работает, только если ds2 уже имеет состояния строк, указывающие на его различия с ds1.Как вы сказали в своем вопросе, это то, что вам нужно сделать.Итак, алгоритм?Вот два: чистый, простой, очевидный способ;и адаптация sort-merge join .Нет способа обойти каждую строку ds2, но второй алгоритм пытается уменьшить объем поиска на ds1, ожидая упорядочения данных.

1) Простой, чистый, очевидный;используя DataRowCollection.Find (pk) и object []. SequenceEqual ().Первичный ключ требуется в каждой таблице, но упорядочение данных не требуется, а тип первичного ключа не имеет значения.

for (int i = 0; i < ds2.Tables.Count; i++)
{
    foreach (DataRow dr in ds2.Tables[i].Rows)
    {
        DataRow drOrig = ds1.Tables[i].Rows.Find(dr[0]);
        if (drOrig != null)
        {
            if (!drOrig.ItemArray.SequenceEqual(dr.ItemArray))
            {
                dr.SetModified();
            }
        }
        else
        {
            dr.SetAdded();
        }
    }
}

ds1.Merge(ds2);

2) Более грубый, более сложный;все еще используя объект []. SequenceEqual ().Данные должны быть упорядочены, хотя идентификатор 'pk' / row не обязательно должен быть уникальным.Тем не менее, его тип должен быть известен для каждой отдельной таблицы, и если типы различаются, вы не можете просто циклически проходить по таблицам.

// Assuming first column of each table is int, primary key; and that all data are ordered by pk.
for (int i = 0; i < ds2.Tables.Count; i++)
{
    int indexDs1 = 0
    int indexDs2 = 0;
    DataRow nextDs1Row = ds1.Tables[i].Rows[indexDs1];
    DataRow nextDs2Row = ds2.Tables[i].Rows[indexDs2];
    int nextDs1Pk = (int)nextDs1Row[0];
    int nextDs2Pk = (int)nextDs2Row[0];
    while ((indexDs1 < ds1.Tables[i].Rows.Count) && (indexDs2 < ds2.Tables[i].Rows.Count))
    {
        if (nextDs1Pk == nextDs2Pk)
        {
            // Set row state to modified if any differences exist.
            if (!nextDs1Row.ItemArray.SequenceEqual(nextDs2Row.ItemArray))
            {
                nextDs2Row.SetModified();
            }
            // Advance both iterators by one row.
            indexDs1++;
            if (indexDs1 < ds1.Tables[i].Rows.Count)
            {
                nextDs1Row = ds1.Tables[i].Rows[indexDs1];
                nextDs1Pk = (int)nextDs1Row[0];
            }
            indexDs2++;
            if (indexDs2 < ds2.Tables[i].Rows.Count)
            {
                nextDs2Row = ds2.Tables[i].Rows[indexDs2];
                nextDs2Pk = (int)nextDs2Row[0];
            }
        }
        else if (nextDs1Pk < nextDs2Pk)
        {
            // Advance through ds1, doing nothing, until the next pk of ds2 is reached.
            do
            {
                indexDs1++;
                if (indexDs1 < ds1.Tables[i].Rows.Count)
                {
                    nextDs1Row = ds1.Tables[i].Rows[indexDs1];
                    nextDs1Pk = (int)nextDs1Row[0];
                }
                else
                {
                    break;
                }
            } while (nextDs1Pk < nextDs2Pk);
        }
        else //nextDs1Pk > nextDs2Pk
        {
            // Advance through ds2, setting row state to added, until the next pk of ds1 is reached.
            do
            {
                nextDs2Row.SetAdded();
                indexDs2++;
                if (indexDs2 < ds2.Tables[i].Rows.Count)
                {
                    nextDs2Row = ds2.Tables[i].Rows[indexDs2];
                    nextDs2Pk = (int)nextDs2Row[0];
                }
                else
                {
                    break;
                }
            } while (nextDs1Pk > nextDs2Pk);
        }
    }
}

Если ваша машина хорошо справляется с несколькими задачами, и вам не нужно применятьОграничения внешнего ключа для отдельных таблиц в наборе, я бы поставил анализ строк каждой таблицы как отдельную задачу, запустил их все параллельно, затем объединил таблицы одну за другой, когда задачи завершены.Если этого достаточно, чтобы алгоритм 1 соответствовал вашим требованиям, я бы остановился на этом во имя простоты.Используемые им методы Find () и SequenceEqual (), вероятно, высоко оптимизированы, и алгоритм 2 в моем тестировании работал не намного быстрее.Если ни один из них не достаточно быстр, и вы что-то знаете о своих данных, вы можете улучшить SequenceEqual ().

...