Отклонить изменения в одном DataColumn в DataRow

Я хочу отклонить изменения, внесенные в один DataColumn в DataRow в DataTable.

Я сделал этот тестовый пример:

DataTable table = new DataTable();
table.Columns.Add("testColumn1");
table.Columns.Add("testColumn2");

DataRow row = table.NewRow();
row["testColumn1"] = "This change should be preserved";
row["testColumn2"] = "This change should be rejected";
table.Rows.Add(row);

row.RejectChanges();

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

Я ищу аналогичную функциональность, которая отменяет изменения только для «testcolumn2», например:

row["testColumn2"].RejectChanges();

Я просмотрел документацию для класса DataColumn и не смог найти аналогичный метод для DataRow.RejectChanges:

https://msdn.microsoft.com/en-us/library/system.data.datacolumn(v=vs.110).aspx

Возможно ли это сделать с помощью C # framework или мне нужно использовать альтернативное решение?

Альтернативные решения также приветствуются.


person soberga    schedule 16.02.2016    source источник


Ответы (2)


Вы можете использовать событие DataTable.ColumnChanging. Это срабатывает каждый раз, когда в столбец данных в таблице вносятся изменения.

table.ColumnChanging += OnColumnChanging;

Метод OnColumnChanging проверяет, совпадает ли имя столбца с именем столбца, который я хочу создать резервную копию, и что вызов не исходит из части кода «возврат значения» (см. логическое значение isRevertingChanges).

Если оба эти условия верны, создается резервный столбец (это пропускается, если он уже существует). Наконец, он записывает значение, которое должно быть перезаписано, в резервный столбец строки.

private bool isRevertingChanges;

void OnColumnChanging(object sender, DataColumnChangeEventArgs e)
{
    if (!isRevertingChanges && e.Column.ColumnName.Equals(TestColumn2))
    {
        if (!e.Row.Table.Columns.Contains(TestColumn2Backup))
            e.Row.Table.Columns.Add(TestColumn2Backup);

        e.Row[TestColumn2Backup] = e.Row[TestColumn2];
    }
}

Поскольку критерии отмены изменений в этом случае не имеют значения, я заменил его на if(true), поэтому часть кода для возврата запускается каждый раз.

Сначала он устанавливает для переменной isRevertingChanges значение true (это делается для того, чтобы OnColumnChanging() не создавал резервную копию возвращаемого значения), затем он возвращает столбец обратно к исходному значению и, наконец, устанавливает isRevertingChanges обратно в false, поэтому OnColumnChanging( ) будет продолжать резервное копирование значений при каждом изменении столбца.

if (true)
{
    isRevertingChanges = true;
    row[TestColumn2] = row[TestColumn2Backup];
    isRevertingChanges = false;
}

Вот полный исходный код:

[TestClass]
public class RejectDataColumnChanges
{
    private bool isRevertingChanges;

    private const string TestColumn1 = "testColumn1";
    private const string TestColumn2 = "testColumn2";
    private const string TestColumn2Backup = "testColumn2Backup";

    private const string PreservedMessage = "This change should be preserved";
    private const string RejectedMessage = "This change should be rejected";

    [TestMethod]
    public void RejectDataColumnChangesTest()
    {
        DataTable table = new DataTable("testTable1");
        table.Columns.Add(TestColumn1);
        table.Columns.Add(TestColumn2);

        DataRow row = table.NewRow();
        row[TestColumn1] = PreservedMessage;
        row[TestColumn2] = PreservedMessage;
        table.Rows.Add(row);

        table.ColumnChanging += OnColumnChanging;

        row[TestColumn2] = RejectedMessage;

        Assert.AreEqual(PreservedMessage, row[TestColumn1]);
        Assert.AreEqual(RejectedMessage, row[TestColumn2]);
        Assert.AreEqual(PreservedMessage, row[TestColumn2Backup]);

        if (true)
        {
            isRevertingChanges = true;
            row[TestColumn2] = row[TestColumn2Backup];
            isRevertingChanges = false;
        }

        Assert.AreEqual(PreservedMessage, row[TestColumn1]);
        Assert.AreEqual(PreservedMessage, row[TestColumn2]);
        Assert.AreEqual(PreservedMessage, row[TestColumn2Backup]);
    }

    void OnColumnChanging(object sender, DataColumnChangeEventArgs e)
    {
        if (!isRevertingChanges && e.Column.ColumnName.Equals(TestColumn2))
        {
            if (!e.Row.Table.Columns.Contains(TestColumn2Backup))
                e.Row.Table.Columns.Add(TestColumn2Backup);

            e.Row[TestColumn2Backup] = e.Row[TestColumn2];
        }
    }
}
person tmagnussen    schedule 31.03.2016

Мне кажется, что самое простое решение - установить значение столбца в исходное значение с помощью DataRowVersion:

row["testColumn2"] = row["testColumn2", DataRowVersion.Original];

В этом подходе есть одна проблема, если вы используете транзакцию для объединения некоторых обновлений. Допустим, в транзакции вы вызываете Adapter.Update для записи изменений в БД, но БД отклоняет их из-за нарушения ограничения. Даже когда я вызываю transaction.RollBack(), я все равно получаю новую версию, когда запрашиваю оригинал.

Как будто .Net вызывает AcceptChanges, не убедившись, что транзакция не будет отменена. Для этого может потребоваться отдельный вопрос к Stack Overflow, чтобы получить решение.

person shindigo    schedule 16.09.2016