Problem:
An ADO.Net Dataset uses Optimistic Concurrency by default. If an attempt is made to update a row to the database when the row no longer exists in the database then the result is the error: Concurrency violation: the UpdateCommand affected 0 of the expected 1 records.
I am trying to give a scenario where that error can occur.
// data row has been added DataRow dr= null;
dtTab = (DataTable)Session("dtTab");
dr = dtTab.Rows(e.RowIndex);
dr.Delete();
dtTab.AcceptChanges();
// If Acceptchanges() being not called, row status will be
//detached, that will not be updated to database.
//Without updating database Acceptchanges() called.Row status
//changed to deleted. If this update to database,
// it will give concurrency error-
// because row no longer exist in database. |
The reason for the error became apparent. The records in the row in the table didn't exist in the database. However, the DeleteCommand was trying to remove them from the Database. And when the data adapter class attempts to delete a record and doesn't see any rows being changed, it assumes that a concurrency violation has occured.
The solution was to take a little more control of the deletion process.
dataAdapter.ContinueUpdateOnError = true;
dataAdapter.ContinueUpdateOnError = true;
dataAdapter.Update(reportsData);
if (reportsData.ReportColumn.HasErrors) {
DataRow[] drs = reportsData.ReportColumn.GetErrors();
foreach (DataRow dr in drs) {
if (dr.RowError.Substring(21) == "Concurrency violation") {
reportsData.ReportColumn.RemoveReportColumnRow((ReportsData.ReportColumnRow)dr);
}
}
reportsData.ReportColumn.AcceptChanges();
// If the dataset still has errors, then an exception needs to be thrown
if (reportsData.ReportColumn.HasErrors) {
throw new DataException("An exception was raised while updating the ReportColumn data table: " + reportsData.ReportColumn.GetErrors()(0).RowError);
}
} |
The ContinueUpdateOnError property is used to stop the aborting of the updates on an exception. Once this is done, we check to see if the data table has any errors. If so, we make sure that every row that has a concurrency violation is removed from the Dataset. The AcceptChanges method call is required to update the HasErrors flag, if all of the errors had been eliminated in this manner.
The following table for your understanding of the Data Row and it's status.
The article given for understanding data set row status.
Execution Sequence
|
Row Event |
Row Status |
Accept Changes() called |
Result. |
1 |
Add |
Added |
No |
Row Added |
2 |
Delete |
Detached |
No |
After deletion row is detached it will not send to database until AcceptChanges()called. |
3 |
|
|
Yes |
Row will be deleted, call database and update |
|
|
|
|
|
1 |
Add |
Added |
No |
Row Added |
2 |
|
|
Yes |
Without updating in Database |
3 |
|
Unchanged |
No |
Added row status changed to unchanged |
4 |
Delete |
Deleted |
No |
Row is not exist in database
It causes Concurrency violation |
// data row has been added DataRow dr = null;
dtTab =(DataTable)Session("dtTab");
dr = dtTab.Rows(e.RowIndex);
dr.Delete();
dtAdapt.Update(dtTab); //without AcceptChanges(), update data in database. Once AcceptChanges() called row will //be marked as deleted. It will find in database table. //If you have row //in Table and you have fetched that trying to delete and commit AcceptChanges() //then it will delete from database. |
I have explained in the above solution why and where we can use AcceptChanges() in a dataset.
I have given some idea for AcceptChanges() and Update().
DataSet.AcceptChanges()
1 When AcceptChanges is being called on the DataSet, the DataRow object will finish their edits successfully.
2 RowState property changes to
1. New Row - Added
2. Modified Rows - unchanged
3. Deleted Rows - Removed
DataAdapter.Update()
When the Update method is being called, the DataAdapter will see RowState Property, and executes respective statements INSERT, UPDATE, or DELETE.
Conclusion
DataAdapter.Update() will recognize only those rows that have changed RowStates.
DataSet.AcceptChanges() sets the RowState of all rows to unchanged.
So any other method attempted to be called after the AcceptChanges() method has been called will not see any changes to update !!