Overview
If a dataset contains constraints (such as a UNIQUE constraint), updating a column in a record can violate the
constraint: After you have finished updating one column but before you get to the next
one, the record can temporarily be in an error state. For example, imagine that
you have a data table in your dataset with two columns that do not allow null values. As
soon as you start to write a new record there will always be a null value in at least one
of the columns (you can only write one column at a time). If there were no mechanism to
allow temporary constraint suspension, an error would be raised every time after writing
the first column and before writing the second.
To temporarily suspend constraints
in a DataRow:
-
Before changing data in a data row, call the DataRow object's
BeginEdit method.
(Note: Changes you make to the
row after calling BeginEdit are saved.)
-
Make the updates to that row.
-
Call the EndEdit method to commit changes to the row and
re-enable constraint checking.
The RowChanging event is raised.
BeginEdit and EndEdit
Use the BeginEdit method to put a DataRow into Edit Mode. In this mode, events
are temporarily suspended allowing the user to make multiple changes to more than one
row without triggering validation rules. For example, if you need to ensure that the
value of the column for a total amount is equal to the values for the debit and credit
columns in a row, you can put each of the rows into edit mode to suspend the validation
of the row values until the user attempts to commit the values.
The BeginEdit method is called implicitly when the user changes the
value of a data-bound control; the EndEdit method is called implicitly when you
invoke the DataTable object's AcceptChanges method. While in this edit mode, the
DataRow stores representations of the original and new proposed values.
Therefore, as long as the EndEdit method has not been called, you can retrieve either the
original or proposed version by passing either DataRowVersion.Original or
DataRowVersion.Proposed for the version parameter of the Item property. You can
also cancel any edits at this time by invoking the CancelEdit method.
To see if the row contains an original or proposed value, call the
HasVersion method.
Example
The example creates a simple DataTable with one DataColumn and five
DataRow objects, and a UniqueConstraint. A RowChanged event handler is also added to
monitor when the row's value is changing. After invoking BeginEdit on the existing rows,
the constraint and event are temporarily disabled and the original and proposed values
are printed. The BeginEdit is again invoked to set two rows to the same value. When
EndEdit is called, the UniqueConstraint is enforced on the identical values.
Additional, we log an entry to the System
Log:
Here is the C# Code
using System;
using System.Data;
namespace Akadia.DataRowEdit
{
// Shows DataRow Editing
public class DataRowEdit
{
public DataRowEdit()
{
ShowDataRowEdit();
}
public void ShowDataRowEdit()
{
// Create the DateTable
DataTable tabTest =
new DataTable("TestTable");
// Crate a Column
DataColumn colTest =
new DataColumn("colTest",Type.GetType("System.Int32"));
// Hook our own RowChanged Event Handler to the DataTable
tabTest.RowChanged +=
new DataRowChangeEventHandler(myRowChangedHandler);
// Add the Column to the DataTable
tabTest.Columns.Add(colTest);
// Add a UniqueConstraint to the Column in the DataTable
tabTest.Constraints.Add(new UniqueConstraint(colTest));
// Add five Rows
DataRow rowTest;
Console.WriteLine("\n*** Add five Rows to the DataTable\n");
for(int i=0; i<5;
i++)
{
// RowChanged Event will occur for every addition!
rowTest = tabTest.NewRow();
rowTest["colTest"]= i;
tabTest.Rows.Add(rowTest);
}
// Accept initial Values
tabTest.AcceptChanges();
Console.WriteLine("\n*** Accept initial Values");
// Invoke BeginEdit on each Row
Console.WriteLine("\n*** Begin Edit on each Row, show RowVersion on each\n");
foreach(DataRow myRow
in tabTest.Rows)
{
myRow.BeginEdit();
// Add 10 to the inital Values
// RowChanged Event will occur for every change!
myRow["colTest"] = (int) myRow["colTest"] + 10;
// Show RowVersion
Console.Write("\t Original \t" + myRow["colTest",DataRowVersion.Original]);
Console.Write("\t Proposed \t" + myRow["colTest",DataRowVersion.Proposed] + "\n");
}
// Accept the Changes
Console.WriteLine("\n");
tabTest.AcceptChanges();
Console.WriteLine("\n*** Accept the Changes()\n");
// Change two Rows to identical values after invoking BeginEdit.
tabTest.Rows[0].BeginEdit();
// Begin Edit on First Row
tabTest.Rows[1].BeginEdit();
// Begin Edit on Second Row
tabTest.Rows[0]["colTest"]= 100; // Change first
Row
tabTest.Rows[1]["colTest"]= 100; // Violate Unique
Constraint
try
{
// Now invoke EndEdit, this will cause the
// UniqueConstraint to be enforced
tabTest.Rows[0].EndEdit();
tabTest.Rows[1].EndEdit();
}
catch(Exception e)
{
// Process Exception, add Message to System Log and
return
System.Diagnostics.EventLog log = new System.Diagnostics.EventLog();
log.Source = "ShowDataRowEdit";
log.WriteEntry(e.ToString());
Console.WriteLine("\n*** Exception of type {0} occurred.", e.GetType());
}
}
// Process RowChanged
Event
private void myRowChangedHandler(object
sender, System.Data.DataRowChangeEventArgs e)
{
DataTable t =
(DataTable) sender;
Console.WriteLine("RowChanged: " + e.Action.ToString() + "\t" + e.Row.ItemArray[0]);
}
// The main entry point
for the application.
[STAThread]
static void Main(string[] args)
{
DataRowEdit
dataRowEdit;
dataRowEdit = new
DataRowEdit();
}
}
}
|