Transactional behavior on DataTables
DataTables publish a number of events that are useful for taking action on a data change. However, sometimes you need to make transactional changes to a table, where the data is not valid until several changes have completed. The canonical example is transferring money between accounts; observers should not display the account balances until both the credit and debit have completed. DataTable.BeginLoadData offers a way to suspend notifications, but it only works for changes made through LoadDataRow.
The below test illustrates the problem:
private int _updateCount = 0;
/// <summary>
/// Fails, because BeginLoadData only suspends update notifications from LoadDataRow
/// </summary>
[Test]
public void SuspendUpdates()
{
DataTable table = new DataTable("Customers");
table.Columns.Add("ID", typeof(Int32));
table.Columns.Add("Name", typeof(string));
/// <summary>
/// Fails, because BeginLoadData only suspends update notifications from LoadDataRow
/// </summary>
[Test]
public void SuspendUpdates()
{
DataTable table = new DataTable("Customers");
table.Columns.Add("ID", typeof(Int32));
table.Columns.Add("Name", typeof(string));
table.Rows.Add(new object[] { 1, "Graham" } );
table.Rows.Add(new object[] { 2, "Smith" } );
table.Rows.Add(new object[] { 2, "Smith" } );
table.RowChanged+=new DataRowChangeEventHandler(table_RowChanged);
table.Rows[0]["Name"] = "Sargeant"; // got married, so change the name
Assertion.AssertEquals("Didn't Update", 1, _updateCount);
Assertion.AssertEquals("Didn't Update", 1, _updateCount);
table.BeginLoadData();
table.Rows[0]["Name"] = "Graham-Sargeant"; // moved to Berkeley, have to hypenate
// this will fail, since we modified the data without using LoadDataRow
Assertion.AssertEquals("Update shouldn't have fired again", 1, _updateCount);
}
// Update handler that increments the updateCount
private void table_RowChanged(object sender, DataRowChangeEventArgs e)
{
_updateCount++;
}
table.Rows[0]["Name"] = "Graham-Sargeant"; // moved to Berkeley, have to hypenate
// this will fail, since we modified the data without using LoadDataRow
Assertion.AssertEquals("Update shouldn't have fired again", 1, _updateCount);
}
// Update handler that increments the updateCount
private void table_RowChanged(object sender, DataRowChangeEventArgs e)
{
_updateCount++;
}