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));
   table.Rows.Add(new object[] { 1, "Graham" } );
   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);
   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++;
  }

No Comments