DataSet Merge и AcceptChanges для получения DiffGram - PullRequest
2 голосов
/ 29 июня 2011

У меня есть два набора данных XML, ds1 и ds2. Я читаю эти наборы данных с помощью .ReadXML (name, XmlReadMode.ReadSchema). Я пытаюсь получить DiffGram с различиями между ними, используя объединенный набор данных, как показано ниже.

DataSet ds3 = new DataSet();
ds3.Merge(ds1);
ds3.AcceptChanges();
ds3.Merge(ds2);

DataSet ds4 = ds3.GetChanges();

ds4.WriteXml("ds4.xml", XmlWriteMode.DiffGram);

DS1 и DS2 каждый содержит несколько элементов. Я создал ds2, скопировав файл ds1 и изменив одну из записей.

Однако, когда я смотрю на ds4.xml после выполнения, он показывает все наборы записей в ds1 и все записи в ds2 (поэтому он показывает дубликаты записей), а обновления ds2 отображаются как ... diffgr : hasChanges = "вставлен">. Похоже, что это только вставка, а не обновление существующих записей.

Как я могу получить DS4, чтобы показать только изменения, которые были сделаны в DS2?

1 Ответ

3 голосов
/ 29 июня 2011

Такое поведение вставки по сравнению с обновлением обычно происходит из-за отсутствия определенных первичных ключей. Вы установили первичные ключи на столах? Вот как столбцы сопоставляются во время слияния. За MSDN (выделено мое):

При объединении нового исходного набора данных в цель, любые исходные строки с Значение DataRowState без изменений, Изменены или удалены , соответствующие целевые строки с одинаковым первичным ключом Значения . Исходные строки с Значение DataRowState добавлено соответствует новым целевым строкам с те же значения первичного ключа как новый исходные строки.

Поэтому для каждого DataTable следует установить свойство PrimaryKey . Я написал подробный пример этого на странице MSDN DataTable.Merge несколько лет назад. Вы можете посмотреть на эту запись здесь: Слияние с использованием первичных ключей для ожидаемых результатов .

Краткий пример такого подхода:

DataTable dt1 = new DataTable();
dt1.Columns.Add("ID", typeof(int));
dt1.Columns.Add("Customer", typeof(string));
dt1.PrimaryKey = new[] { dt1.Columns["ID"] };
dt1.Rows.Add(new object[] { 1, "Ahmad" });

DataTable dt2 = new DataTable();
dt2.Columns.Add("ID", typeof(int));
dt2.Columns.Add("Customer", typeof(string));
dt2.PrimaryKey = new[] { dt2.Columns["ID"] };
dt2.Rows.Add(new object[] { 1, "Mageed" });

// try without primary keys and it'll add a new record
dt1.Merge(dt2);

РЕДАКТИРОВАТЬ: относительно вашего комментария, вы можете отклонить изменения в объединенных строках, которые на самом деле не были изменены, пройдя таблицу с помощью кода ниже. Метод, который принимает DataTable, будет более аккуратным. Важно, чтобы этот код использовался до вызова метода DataTable.AcceptChanges() , в противном случае состояния строк будут отброшены.

С LINQ:

foreach (DataRow row in dt1.Rows)
{
    if (row.RowState == DataRowState.Modified)
    {
        var original = dt1.Columns.Cast<DataColumn>()
                          .Select(c => row[c, DataRowVersion.Original]);

        bool isUnchanged = row.ItemArray.SequenceEqual(original);
        if (isUnchanged)
        {
            row.RejectChanges();
        }
    }
}

Если LINQ не поддерживается:

foreach (DataRow row in dt1.Rows)
{
    if (row.RowState == DataRowState.Modified)
    {
        bool isUnchanged = true;
        foreach (DataColumn col in dt1.Columns)
        {
            if (!row[col.ColumnName].Equals(row[col.ColumnName, DataRowVersion.Original]))
            {
                isUnchanged = false;
                break;
            }
        }

        if (isUnchanged)
        {
            row.RejectChanges();
        }
    }
}

Вы можете позвонить dt1.AcceptChanges() после того, как это будет сделано.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...