Showing posts with label ADO.NET. Show all posts
Showing posts with label ADO.NET. Show all posts

Saturday, June 12, 2010

The LoadDataRow and Delete Methods of DataTable

Oftentimes we encounter problems when we perform update using LoadDataRow or rollback data using RejectChanges after the Delete method. Why do the methods sometimes not do what we want?

Googling a solution for LoadDataRow, we may find that most people resolve the update performed by LoadDataRow must call DataTable.AcceptChanges first. Does this solution work for you 100%? There are still some unresolved posts left unanswered. They follow the solution to call AcceptChanges but the problem still exists. Why?

Deleting a DataRow and then immediately performing RejectAccepts to rollback cause us to receive System.Data.RowNotInTableException. What is it going on? Is the DataRow marked as Deleted? Why can't I rollback?

The above problems are related to either the RowState of a DataRow or if we set up the constraints on DataTable correctly.

continue Assuming there is no constraint problem, the DataRow must be either Unchanged or Modified when we perform an update using the LoadDataRow method on an existing DataRow. The same principle applies to the RejectChanges after calling the Delete method. Apparently, the operations requires an Original version existed for the DataRow. When the RowState of DataRow is Unchanged or Modified, an Original version of the DataRow has been created/existed. Thus, any operations after it won't cause a problem.

continueIf you receive a System.Data.ConstraintException in regard to System.Data.UniqueConstraint.CheckConstraint, please ensure the primary key set up properly. Most likely, setting the Unique property of a DataColumn without primary key to true will cause this problem to occur.

continueIf you receive a System.Data.ConstraintException in regard to System.Data.DataTable.EnableConstraints, please ensure an Original version existed for the DataRow. It means the RowState of the DataRow is still in the state of Added and you need to commit changes first by calling the AcceptChanges method to update the state to Unchanged.

continueSimilarly, if you receive a System.Data.RowNotInTableException when you try to roll back the DataRow after having called the Delete method, a AcceptChanges call is required before the Delete method. After AcceptChanges, an Original version of the DataRow is created and the RowState of the DataRow is set to Unchanged. From this state onwards, any modification including the LoadDataRow method, or calling the Delete method and then the RejectChanges method can be performed.

To sum up what the RowState means is described in the following table.
DetachedThe DataRow is created but it hasn't been added to a DataTable yet. Since it does not exist in a DataTable, no operations can be performed at the DataTable level.
AddedThe DataRow is added to a DataTable but the DataTable has not accepted changes yet. At this stage, it requires AcceptChanges to create Original version for other update operations including rollback.
UnchangedThe DataRow has not changed since the last AcceptChanges call. At this stage, an Original version of the DataRow has already existed. Thus, any operations can be performed without a problem.
ModifiedThe DataRow has been modified since the last AcceptChanges call. Like Unchanged, an Original version of the DataRow has already existed in this stage. A DataRow with Modified row state can continously be modified but the RejectChanges will only roll the data back to the last AcceptChanges call. Any modification made in between is disgarded because the Original version of the DataRow is only pointing the copy when the last AcceptChanges is called.
DeletedThe DataRow was deleted by using the Delete method of the DataRow only when the RowState of the DataRow is Unchanged or Modified.

I also attach some test results I conducted for reference.

Friday, June 11, 2010

About DataRow.Delete, .AcceptChanges and .RejectChanges

See The LoadDataRow and Delete Methods of DataTable for intention.

Purpose

The following 3 tests [ Test 1 | Test 2 | Test 3 ] tell you about in which situation you can roll back your data and when you cannot.

This page is generated by the application developed in C# under Visual 2008 Profession SP + .NET 3.5 SP1 on Windows XP Professional SP3.

Test 1: No AcceptChanges before deletion
  • Set up a DataTable with 2 rows; so the initial RowState of all DataRows is Added.
  • Without AcceptChanges, immediately delete the 2nd DataRow using Delete method.
  • The RowState of the deleted row is not Deleted but Detached; The result is different from what it is said in the documentation [According to MSDN, it is currently supported in: 4, 3.5, 3.0, 2.0, 1.1, 1.0]. Please also see the test foot notes in blue.
  • Then RejectChanges after deletion; unfortunately, the System.Data.RowNotInTableException is received.

EmpIdFirstNameLastNameSalaryLastName and FirstNameRowState
A123456789BettyeWilliams11.00Williams, BettyeAdded
B223456789RexBloomer12.00Bloomer, RexAdded

Initial state: [B223456789, Rex] RowState: Added
Version: Original doesn't not exist.
Version: Current Value: Rex
Version: Proposed doesn't not exist.
Version: Default Value: Rex

Using Delete method to delete [B223456789, Rex] at RowState: Added...
EmpIdFirstNameLastNameSalaryLastName and FirstNameRowState
A123456789BettyeWilliams11.00Williams, BettyeAdded

The deleted row after deletion: RowState: Detached
Version: Original doesn't not exist.
Version: Current doesn't not exist.
Version: Proposed doesn't not exist.
Version: Default doesn't not exist.

This row has been removed from a table and does not have any data.  BeginEdit() will allow creation of new data in this row.
System.Data.RowNotInTableException
at System.Data.DataRow.GetDefaultRecord() at System.Data.DataColumn.CheckNullable(DataRow row) at System.Data.DataColumn.CheckColumnConstraint(DataRow row, DataRowAction action) at System.Data.DataTable.RaiseRowChanging(DataRowChangeEventArgs args, DataRow eRow, DataRowAction eAction, Boolean fireEvent) at System.Data.DataTable.SetNewRecordWorker(DataRow row, Int32 proposedRecord, DataRowAction action, Boolean isInMerge, Int32 position, Boolean fireEvent, Exception& deferredException) at System.Data.DataTable.SetNewRecord(DataRow row, Int32 proposedRecord, DataRowAction action, Boolean isInMerge, Boolean fireEvent) at System.Data.DataTable.RollbackRow(DataRow row) at System.Data.DataRow.RejectChanges() ...

After error: RowState: Detached
Version: Original doesn't not exist.
Version: Current doesn't not exist.
Version: Proposed doesn't not exist.
Version: Default doesn't not exist.

  • By definition of DataRow.Delete method, the row should have been marked as Deleted.
  • According to this, this bug should have been fixed in VS 2008. Apparently, it still exists. Or there may be a typo in the document. Originally it said, "If the RowState of the row is Added, the RowState becomes Detached and the row is removed from the table when you call AcceptChanges." Perhaps, it is meant to say, ""If the RowState of the row is Added, the RowState becomes Detached and the row is removed from the table when you call RejectChanges." Then everything will become and make more sense.
  • Because DataRow.RowState is set to Detached, we cannot roll it back by using RejectChanges.


Test 2: AcceptChanges before deletion
  • Set up a DataTable with 2 rows; so the initial RowState of all DataRows is Added.
  • Then AcceptChanges, which changes the RowState from Added to Unchanged.
  • Delete the 2nd DataRow using Delete method. The RowState of the 2nd DataRow is marked as Deleted now.
  • Immdiately RejectChanges after deletion, which changes the RowState from Deleted back to Unchanged

EmpIdFirstNameLastNameSalaryLastName and FirstNameRowState
A123456789BettyeWilliams11.00Williams, BettyeAdded
B223456789RexBloomer12.00Bloomer, RexAdded

Initial state: [B223456789, Rex] RowState: Added
Version: Original doesn't not exist.
Version: Current Value: Rex
Version: Proposed doesn't not exist.
Version: Default Value: Rex

AcceptChanges. [B223456789, Rex] RowState: Unchanged
Version: Original Value: Rex
Version: Current Value: Rex
Version: Proposed doesn't not exist.
Version: Default Value: Rex

Using Delete method to delete [B223456789, Rex] at RowState: Unchanged...
EmpIdFirstNameLastNameSalaryLastName and FirstNameRowState
A123456789BettyeWilliams11.00Williams, BettyeUnchanged
?????Deleted

The deleted row after deletion: RowState: Deleted
Version: Original Value: Rex
Version: Current doesn't not exist.
Version: Proposed doesn't not exist.
Version: Default doesn't not exist.

RejectChanges:
EmpIdFirstNameLastNameSalaryLastName and FirstNameRowState
A123456789BettyeWilliams11.00Williams, BettyeUnchanged
B223456789RexBloomer12.00Bloomer, RexUnchanged

[B223456789, Rex] RowState: Unchanged
Version: Original Value: Rex
Version: Current Value: Rex
Version: Proposed doesn't not exist.
Version: Default Value: Rex

  • After deletion using Delete method, the RowState is set to Deleted.
  • Thus, RejectChanges can be used to roll back the DataRow to the point where the AcceptChanges method is last called.
  • The RowState of the deleted row is also rolled back to Unchanged. Everything looks exactly like before deletion.

Test 3: AcceptChanges, modification and then deletion
  • Set up a DataTable with 2 rows; so the initial RowState of all DataRows is Added.
  • Then AcceptChanges, which changes the RowState from Added to Unchanged.
  • Start BeginEdit ... EndEdit block to modify the 2nd row. Change the FirstName from Rex to Susan.
  • The expression column LastName and FirstName remains unchanged until the EndEdit method is called while FirstName is modified before calling EndEdit.
  • Then delete the 2nd DataRow using Delete method. The RowState of the 2nd DataRow is marked as Deleted now.
  • Immdiately RejectChanges after deletion, which changes everything back to the state when the AcceptChanges is last called; thus the RowState is rolled back all the way from Deleted to Unchanged

EmpIdFirstNameLastNameSalaryLastName and FirstNameRowState
A123456789BettyeWilliams11.00Williams, BettyeAdded
B223456789RexBloomer12.00Bloomer, RexAdded

Initial state: [B223456789, Rex] RowState: Added
Version: Original doesn't not exist.
Version: Current Value: Rex
Version: Proposed doesn't not exist.
Version: Default Value: Rex

AcceptChanges. [B223456789, Rex] RowState: Unchanged
Version: Original Value: Rex
Version: Current Value: Rex
Version: Proposed doesn't not exist.
Version: Default Value: Rex

BeginEdit and modified the 2nd row:
 row.BeginEdit(); row["FirstName"] = "Susan";

EmpIdFirstNameLastNameSalaryLastName and FirstNameRowState
A123456789BettyeWilliams11.00Williams, BettyeUnchanged
B223456789SusanBloomer12.00Bloomer, RexUnchanged
[B223456789, Susan] RowState: Unchanged
Version: Original Value: Rex
Version: Current Value: Rex
Version: Proposed Value: Susan
Version: Default Value: Susan

After EndEdit:
  row.EndEdit();

EmpIdFirstNameLastNameSalaryLastName and FirstNameRowState
A123456789BettyeWilliams11.00Williams, BettyeUnchanged
B223456789SusanBloomer12.00Bloomer, SusanModified
[B223456789, Susan] RowState: Modified
Version: Original Value: Rex
Version: Current Value: Susan
Version: Proposed doesn't not exist.
Version: Default Value: Susan

Using Delete method to delete [B223456789, Susan] at RowState: Modified...
EmpIdFirstNameLastNameSalaryLastName and FirstNameRowState
A123456789BettyeWilliams11.00Williams, BettyeUnchanged
?????Deleted

The deleted row after deletion: RowState: Deleted
Version: Original Value: Rex
Version: Current doesn't not exist.
Version: Proposed doesn't not exist.
Version: Default doesn't not exist.

RejectChanges:
EmpIdFirstNameLastNameSalaryLastName and FirstNameRowState
A123456789BettyeWilliams11.00Williams, BettyeUnchanged
B223456789RexBloomer12.00Bloomer, RexUnchanged

[B223456789, Rex] RowState: Unchanged
Version: Original Value: Rex
Version: Current Value: Rex
Version: Proposed doesn't not exist.
Version: Default Value: Rex

Interesting of this test is that the "LastName and FirstName" column remains unchanged [Bloomer, Rex] after the FirstName has been modified to Susan. The "LastName and FirstName" column is an Expression column set up by expression that contains the values from both FirstName and LastName columns. Changing FirstName will not refect the change immediately in the "FirstName and LastName" column until EndEdit is called.

Wednesday, June 9, 2010

LoadDataRow(object[], bool) and ConstraintException

See The LoadDataRow and Delete Methods of DataTable for intention.


Introduction

In this test, I will use LoadDataRow to perform content update on a DataTable with or without primary key constraint. bool AcceptChanges will be passed as a parameter in LoadDataRow(object[], bool). For result using LoadDataRow(object[], LoadOption), please see this.

When the LoadDataRow method is call, the following statement is used:
   employee.LoadDataRow(
      new object[] { "B223456789", "Denise", "Miller", 13.00 },
      false);  // don't AcceptChanges
When primary key is applied, the following statement is used and it will be executed before the LoadDataRow method:
   employee.PrimaryKey = new DataColumn[] {eid}; // eid is the EmpId column   

The DataTable used for the test has the five (5) columns and initially is populated with 2 sample data rows.
ColumnNameEmpIdFirstNameLastNameSalaryLastName and FirstName **
DataTypestringstringstringdecimalstring
MaxLength1035-1-170
Uniquetruefalsefalsefalsefalse
AllowDBNullfalsefalsefalsetruetrue

** The column of LastName and FirstName is defined as an expression column containing the values from the column of LastName and the column of FirstName.

Every test is based on this table with the initial sample data. The 2nd row is the target to update by using the LoadDataRow method. A grid shown in each test is represented the final result of the DataTable even though the update performed by the LoadDataRow method may fail. Execution messages about the RowState of the 2nd row and its versions are shown afterwards. For clarity, the initial state of the 2nd row is also attached to each test for reference.

The rest of the page is generated by the application developed in C# under Visual 2008 Profession SP + .NET 3.5 SP1 on Windows XP Professional SP3.


Set up a DataTable with 2 rows
- EmpId is the unique key (eid.Unique = true).
- Primary key is not set up initially.

  • Initial Table:
  • EmpIdFirstNameLastNameSalaryLastName and FirstName
    A123456789BettyeWilliams11.00Williams, Bettye
    B223456789RexBloomer12.00Bloomer, Rex

  • Status duing execution:
  • Initial state: [B223456789, Rex] RowState: Added
    Version: Original doesn't not exist.
    Version: Current Value: Rex
    Version: Proposed doesn't not exist.
    Version: Default Value: Rex


No primary key applied
Expect errors [System.Data.UniqueConstraint.CheckConstraint]!
The last row remains unchanged.

  • Resulted DataTable:
  • EmpIdFirstNameLastNameSalaryLastName and FirstName
    A123456789BettyeWilliams11.00Williams, Bettye
    B223456789RexBloomer12.00Bloomer, Rex

  • Status duing execution:
  • Initial state: [B223456789, Rex] RowState: Added
    Version: Original doesn't not exist.
    Version: Current Value: Rex
    Version: Proposed doesn't not exist.
    Version: Default Value: Rex

    Executing LoadDataRow(...)
    Column 'EmpId' is constrained to be unique.  Value 'B223456789' is already present.
    System.Data.ConstraintException
    at System.Data.UniqueConstraint.CheckConstraint(DataRow row, DataRowAction action) at System.Data.DataTable.RaiseRowChanging(DataRowChangeEventArgs args, DataRow eRow, DataRowAction eAction, Boolean fireEvent) at System.Data.DataTable.SetNewRecordWorker(DataRow row, Int32 proposedRecord, DataRowAction action, Boolean isInMerge, Int32 position, Boolean fireEvent, Exception& deferredException) at System.Data.DataTable.InsertRow(DataRow row, Int32 proposedID, Int32 pos, Boolean fireEvent) at System.Data.DataRowCollection.Add(Object[] values) at System.Data.DataTable.UpdatingAdd(Object[] values) at System.Data.DataTable.LoadDataRow(Object[] values, Boolean fAcceptChanges) ...

    After error: [B223456789, Rex] RowState: Added
    Version: Original doesn't not exist.
    Version: Current Value: Rex
    Version: Proposed doesn't not exist.
    Version: Default Value: Rex


Primary key applied, no AcceptChanges before or after LoadDataRow
Expect errors [System.Data.UniqueConstraint.CheckConstraint]!
The last row remains unchanged.

  • Resulted DataTable:
  • EmpIdFirstNameLastNameSalaryLastName and FirstName
    A123456789BettyeWilliams11.00Williams, Bettye
    B223456789RexBloomer12.00Bloomer, Rex

  • Status duing execution:
  • Initial state: [B223456789, Rex] RowState: Added
    Version: Original doesn't not exist.
    Version: Current Value: Rex
    Version: Proposed doesn't not exist.
    Version: Default Value: Rex

    Executing LoadDataRow(...)
    Column 'EmpId' is constrained to be unique.  Value 'B223456789' is already present.
    System.Data.ConstraintException
    at System.Data.UniqueConstraint.CheckConstraint(DataRow row, DataRowAction action) at System.Data.DataTable.RaiseRowChanging(DataRowChangeEventArgs args, DataRow eRow, DataRowAction eAction, Boolean fireEvent) at System.Data.DataTable.SetNewRecordWorker(DataRow row, Int32 proposedRecord, DataRowAction action, Boolean isInMerge, Int32 position, Boolean fireEvent, Exception& deferredException) at System.Data.DataTable.InsertRow(DataRow row, Int32 proposedID, Int32 pos, Boolean fireEvent) at System.Data.DataTable.UpdatingAdd(Object[] values) at System.Data.DataTable.LoadDataRow(Object[] values, Boolean fAcceptChanges) ...

    After error: [B223456789, Rex] RowState: Added
    Version: Original doesn't not exist.
    Version: Current Value: Rex
    Version: Proposed doesn't not exist.
    Version: Default Value: Rex


No primary key, AcceptChanges before LoadDataRow
Expect errors [System.Data.UniqueConstraint.CheckConstraint]!
The last row remains unchanged.

  • Resulted DataTable:
  • EmpIdFirstNameLastNameSalaryLastName and FirstName
    A123456789BettyeWilliams11.00Williams, Bettye
    B223456789RexBloomer12.00Bloomer, Rex

  • Status duing execution:
  • Initial state: [B223456789, Rex] RowState: Added
    Version: Original doesn't not exist.
    Version: Current Value: Rex
    Version: Proposed doesn't not exist.
    Version: Default Value: Rex

    Apply AcceptChanges(): [B223456789, Rex] RowState: Unchanged
    Version: Original Value: Rex
    Version: Current Value: Rex
    Version: Proposed doesn't not exist.
    Version: Default Value: Rex

    Executing LoadDataRow(...)
    Column 'EmpId' is constrained to be unique.  Value 'B223456789' is already present.
    System.Data.ConstraintException
    at System.Data.UniqueConstraint.CheckConstraint(DataRow row, DataRowAction action) at System.Data.DataTable.RaiseRowChanging(DataRowChangeEventArgs args, DataRow eRow, DataRowAction eAction, Boolean fireEvent) at System.Data.DataTable.SetNewRecordWorker(DataRow row, Int32 proposedRecord, DataRowAction action, Boolean isInMerge, Int32 position, Boolean fireEvent, Exception& deferredException) at System.Data.DataTable.InsertRow(DataRow row, Int32 proposedID, Int32 pos, Boolean fireEvent) at System.Data.DataRowCollection.Add(Object[] values) at System.Data.DataTable.UpdatingAdd(Object[] values) at System.Data.DataTable.LoadDataRow(Object[] values, Boolean fAcceptChanges) ...

    After error: [B223456789, Rex] RowState: Unchanged
    Version: Original Value: Rex
    Version: Current Value: Rex
    Version: Proposed doesn't not exist.
    Version: Default Value: Rex


Primary key applied, AcceptChanges before LoadDataRow
No error! The last row is updated.

  • Resulted DataTable:
  • EmpIdFirstNameLastNameSalaryLastName and FirstName
    A123456789BettyeWilliams11.00Williams, Bettye
    B223456789DeniseMiller13.00Miller, Denise

  • Status duing execution:
  • Initial state: [B223456789, Rex] RowState: Added
    Version: Original doesn't not exist.
    Version: Current Value: Rex
    Version: Proposed doesn't not exist.
    Version: Default Value: Rex

    Apply AcceptChanges(): [B223456789, Rex] RowState: Unchanged
    Version: Original Value: Rex
    Version: Current Value: Rex
    Version: Proposed doesn't not exist.
    Version: Default Value: Rex

    Executing LoadDataRow(...)
    After LoadDataRow: [B223456789, Denise] RowState: Modified
    Version: Original Value: Rex
    Version: Current Value: Denise
    Version: Proposed doesn't not exist.
    Version: Default Value: Denise


No primary key, LoadDataRow in conjunction with Begin/EndLoadData
Expect errors [System.Data.DataTable.EnableConstraints()]!
Duplicate rows are found.

  • Resulted DataTable:
  • EmpIdFirstNameLastNameSalaryLastName and FirstName
    A123456789BettyeWilliams11.00Williams, Bettye
    B223456789RexBloomer12.00Bloomer, Rex
    B223456789DeniseMiller13.00Miller, Denise

  • Status duing execution:
  • Initial state: [B223456789, Rex] RowState: Added
    Version: Original doesn't not exist.
    Version: Current Value: Rex
    Version: Proposed doesn't not exist.
    Version: Default Value: Rex

    BeginLoadData(): turn off notification/constraints/indexing.

    Executing LoadDataRow(...)
    After LoadDataRow: [B223456789, Denise] RowState: Added
    Version: Original doesn't not exist.
    Version: Current Value: Denise
    Version: Proposed doesn't not exist.
    Version: Default Value: Denise

    EndLoadData(): turn on validation, constraints, etc.

    Failed to enable constraints. One or more rows contain values violating non-null, unique, or foreign-key constraints.
    System.Data.ConstraintException
    at System.Data.DataTable.EnableConstraints() at System.Data.DataTable.set_EnforceConstraints(Boolean value) at System.Data.DataTable.EndLoadData() ...

    After error: [B223456789, Rex] RowState: Added
    Version: Original doesn't not exist.
    Version: Current Value: Rex
    Version: Proposed doesn't not exist.
    Version: Default Value: Rex


Primary key applied, LoadDataRow in conjunction with Begin/EndLoadData
Expect errors [System.Data.DataTable.EnableConstraints()]!
Duplicate rows are found.

  • Resulted DataTable:
  • EmpIdFirstNameLastNameSalaryLastName and FirstName
    A123456789BettyeWilliams11.00Williams, Bettye
    B223456789RexBloomer12.00Bloomer, Rex
    B223456789DeniseMiller13.00Miller, Denise

  • Status duing execution:
  • Initial state: [B223456789, Rex] RowState: Added
    Version: Original doesn't not exist.
    Version: Current Value: Rex
    Version: Proposed doesn't not exist.
    Version: Default Value: Rex

    BeginLoadData(): turn off notification/constraints/indexing.

    Executing LoadDataRow(...)
    After LoadDataRow: [B223456789, Denise] RowState: Added
    Version: Original doesn't not exist.
    Version: Current Value: Denise
    Version: Proposed doesn't not exist.
    Version: Default Value: Denise

    EndLoadData(): turn on validation, constraints, etc.

    Failed to enable constraints. One or more rows contain values violating non-null, unique, or foreign-key constraints.
    System.Data.ConstraintException
    at System.Data.DataTable.EnableConstraints() at System.Data.DataTable.set_EnforceConstraints(Boolean value) at System.Data.DataTable.EndLoadData() ...

    After error: [B223456789, Rex] RowState: Added
    Version: Original doesn't not exist.
    Version: Current Value: Rex
    Version: Proposed doesn't not exist.
    Version: Default Value: Rex


Primary key applied, LoadDataRow in conjunction with Begin/EndLoadData, ApplyChanges before BeginLoadData
No error! The last row is updated.

  • Resulted DataTable:
  • EmpIdFirstNameLastNameSalaryLastName and FirstName
    A123456789BettyeWilliams11.00Williams, Bettye
    B223456789DeniseMiller13.00Miller, Denise

  • Status duing execution:
  • Initial state: [B223456789, Rex] RowState: Added
    Version: Original doesn't not exist.
    Version: Current Value: Rex
    Version: Proposed doesn't not exist.
    Version: Default Value: Rex

    Apply AcceptChanges(): [B223456789, Rex] RowState: Unchanged
    Version: Original Value: Rex
    Version: Current Value: Rex
    Version: Proposed doesn't not exist.
    Version: Default Value: Rex

    BeginLoadData(): turn off notification/constraints/indexing.

    Executing LoadDataRow(...)
    After LoadDataRow: [B223456789, Denise] RowState: Modified
    Version: Original Value: Rex
    Version: Current Value: Denise
    Version: Proposed doesn't not exist.
    Version: Default Value: Denise

    EndLoadData(): turn on validation, constraints, etc.

    [B223456789, Denise] RowState: Modified
    Version: Original Value: Rex
    Version: Current Value: Denise
    Version: Proposed doesn't not exist.
    Version: Default Value: Denise

LoadDataRow(object[], LoadOption) and ConstraintException

See The LoadDataRow and Delete Methods of DataTable for intention.


Introduction

In this test, I will use LoadDataRow to perform content update on a DataTable with or without primary key constraint. LoadOption is passed in a parameter with this call LoadDataRow(object[], LoadOption). For result using LoadDataRow(object[], bool), please see this.

When the LoadDataRow method is call, the following statement is used:
   employee.LoadDataRow(
      new object[] { "B223456789", "Denise", "Miller", 13.00 },
      LoadOption.OverwriteChanges);
When primary key is applied, the following statement is used and it will be executed before the LoadDataRow method:
   employee.PrimaryKey = new DataColumn[] {eid}; // eid is the EmpId column  

Before presenting the test results, we will first set up a DataTable with 2 rows without primary key constraint. Our DataTable will have the following columns:
ColumnNameEmpIdFirstNameLastNameSalaryLastName and FirstName **
DataTypestringstringstringdecimalstring
MaxLength1035-1-170
Uniquetruefalsefalsefalsefalse
AllowDBNullfalsefalsefalsetruetrue

** The column of LastName and FirstName is defined as an expression column containing the values from the column of LastName and the column of FirstName.

Every test is based on this table with the initial sample data. The 2nd row is the target to update by using the LoadDataRow method. A grid shown in each test is represented the final result of the DataTable even though the update performed by the LoadDataRow method may fail. Execution messages about the RowState of the 2nd row and its versions are shown afterwards. For clarity, the initial state of the 2nd row is also attached to each test for reference.

The rest of the page is generated by the application developed in C# under Visual 2008 Profession SP + .NET 3.5 SP1 on Windows XP Professional SP3.


Set up a DataTable with 2 rows
- EmpId is the unique key (eid.Unique = true).
- Primary key is not set up initially.

  • Initial Table:
  • EmpIdFirstNameLastNameSalaryLastName and FirstName
    A123456789BettyeWilliams11.00Williams, Bettye
    B223456789RexBloomer12.00Bloomer, Rex

  • Status duing execution:
  • Initial state: [B223456789, Rex] RowState: Added
    Version: Original doesn't not exist.
    Version: Current Value: Rex
    Version: Proposed doesn't not exist.
    Version: Default Value: Rex


No primary key applied
Expect errors [System.Data.UniqueConstraint.CheckConstraint]!
The last row remains unchanged.

  • Resulted DataTable:
  • EmpIdFirstNameLastNameSalaryLastName and FirstName
    A123456789BettyeWilliams11.00Williams, Bettye
    B223456789RexBloomer12.00Bloomer, Rex

  • Status duing execution:
  • Initial state: [B223456789, Rex] RowState: Added
    Version: Original doesn't not exist.
    Version: Current Value: Rex
    Version: Proposed doesn't not exist.
    Version: Default Value: Rex

    Executing LoadDataRow(...)
    Column 'EmpId' is constrained to be unique.  Value 'B223456789' is already present.
    System.Data.ConstraintException
    at System.Data.UniqueConstraint.CheckConstraint(DataRow row, DataRowAction action) at System.Data.DataTable.RaiseRowChanging(DataRowChangeEventArgs args, DataRow eRow, DataRowAction eAction, Boolean fireEvent) at System.Data.DataTable.SetNewRecordWorker(DataRow row, Int32 proposedRecord, DataRowAction action, Boolean isInMerge, Int32 position, Boolean fireEvent, Exception& deferredException) at System.Data.DataTable.InsertRow(DataRow row, Int32 proposedID, Int32 pos, Boolean fireEvent) at System.Data.DataTable.LoadRow(Object[] values, LoadOption loadOption, Index searchIndex) at System.Data.DataTable.LoadDataRow(Object[] values, LoadOption loadOption) ...

    After error: [B223456789, Rex] RowState: Added
    Version: Original doesn't not exist.
    Version: Current Value: Rex
    Version: Proposed doesn't not exist.
    Version: Default Value: Rex


Primary key applied, no AcceptChanges before or after LoadDataRow
No error! The last row is updated.

  • Resulted DataTable:
  • EmpIdFirstNameLastNameSalaryLastName and FirstName
    A123456789BettyeWilliams11.00Williams, Bettye
    B223456789DeniseMiller13.00Miller, Denise

  • Status duing execution:
  • Initial state: [B223456789, Rex] RowState: Added
    Version: Original doesn't not exist.
    Version: Current Value: Rex
    Version: Proposed doesn't not exist.
    Version: Default Value: Rex

    Executing LoadDataRow(...)
    After LoadDataRow: [B223456789, Denise] RowState: Unchanged
    Version: Original Value: Denise
    Version: Current Value: Denise
    Version: Proposed doesn't not exist.
    Version: Default Value: Denise


No primary key, AcceptChanges before LoadDataRow
Expect errors [System.Data.UniqueConstraint.CheckConstraint]!
The last row remains unchanged.

  • Resulted DataTable:
  • EmpIdFirstNameLastNameSalaryLastName and FirstName
    A123456789BettyeWilliams11.00Williams, Bettye
    B223456789RexBloomer12.00Bloomer, Rex

  • Status duing execution:
  • Initial state: [B223456789, Rex] RowState: Added
    Version: Original doesn't not exist.
    Version: Current Value: Rex
    Version: Proposed doesn't not exist.
    Version: Default Value: Rex

    Apply AcceptChanges(): [B223456789, Rex] RowState: Unchanged
    Version: Original Value: Rex
    Version: Current Value: Rex
    Version: Proposed doesn't not exist.
    Version: Default Value: Rex

    Executing LoadDataRow(...)
    Column 'EmpId' is constrained to be unique.  Value 'B223456789' is already present.
    System.Data.ConstraintException
    at System.Data.UniqueConstraint.CheckConstraint(DataRow row, DataRowAction action) at System.Data.DataTable.RaiseRowChanging(DataRowChangeEventArgs args, DataRow eRow, DataRowAction eAction, Boolean fireEvent) at System.Data.DataTable.SetNewRecordWorker(DataRow row, Int32 proposedRecord, DataRowAction action, Boolean isInMerge, Int32 position, Boolean fireEvent, Exception& deferredException) at System.Data.DataTable.InsertRow(DataRow row, Int32 proposedID, Int32 pos, Boolean fireEvent) at System.Data.DataTable.LoadRow(Object[] values, LoadOption loadOption, Index searchIndex) at System.Data.DataTable.LoadDataRow(Object[] values, LoadOption loadOption) ...

    After error: [B223456789, Rex] RowState: Unchanged
    Version: Original Value: Rex
    Version: Current Value: Rex
    Version: Proposed doesn't not exist.
    Version: Default Value: Rex


Primary key applied, AcceptChanges before LoadDataRow
No error! The last row is updated.

  • Resulted DataTable:
  • EmpIdFirstNameLastNameSalaryLastName and FirstName
    A123456789BettyeWilliams11.00Williams, Bettye
    B223456789DeniseMiller13.00Miller, Denise

  • Status duing execution:
  • Initial state: [B223456789, Rex] RowState: Added
    Version: Original doesn't not exist.
    Version: Current Value: Rex
    Version: Proposed doesn't not exist.
    Version: Default Value: Rex

    Apply AcceptChanges(): [B223456789, Rex] RowState: Unchanged
    Version: Original Value: Rex
    Version: Current Value: Rex
    Version: Proposed doesn't not exist.
    Version: Default Value: Rex

    Executing LoadDataRow(...)
    After LoadDataRow: [B223456789, Denise] RowState: Unchanged
    Version: Original Value: Denise
    Version: Current Value: Denise
    Version: Proposed doesn't not exist.
    Version: Default Value: Denise


No primary key, LoadDataRow in conjunction with Begin/EndLoadData
Expect errors [System.Data.DataTable.EnableConstraints()]!
Duplicate rows are found.

  • Resulted DataTable:
  • EmpIdFirstNameLastNameSalaryLastName and FirstName
    A123456789BettyeWilliams11.00Williams, Bettye
    B223456789RexBloomer12.00Bloomer, Rex
    B223456789DeniseMiller13.00Miller, Denise

  • Status duing execution:
  • Initial state: [B223456789, Rex] RowState: Added
    Version: Original doesn't not exist.
    Version: Current Value: Rex
    Version: Proposed doesn't not exist.
    Version: Default Value: Rex

    BeginLoadData(): turn off notification/constraints/indexing.

    Executing LoadDataRow(...)
    After LoadDataRow: [B223456789, Denise] RowState: Unchanged
    Version: Original Value: Denise
    Version: Current Value: Denise
    Version: Proposed doesn't not exist.
    Version: Default Value: Denise

    EndLoadData(): turn on validation, constraints, etc.

    Failed to enable constraints. One or more rows contain values violating non-null, unique, or foreign-key constraints.
    System.Data.ConstraintException
    at System.Data.DataTable.EnableConstraints() at System.Data.DataTable.set_EnforceConstraints(Boolean value) at System.Data.DataTable.EndLoadData() ...

    After error: [B223456789, Rex] RowState: Added
    Version: Original doesn't not exist.
    Version: Current Value: Rex
    Version: Proposed doesn't not exist.
    Version: Default Value: Rex


Primary key applied, LoadDataRow in conjunction with Begin/EndLoadData
No error! The last row is updated.

  • Resulted DataTable:
  • EmpIdFirstNameLastNameSalaryLastName and FirstName
    A123456789BettyeWilliams11.00Williams, Bettye
    B223456789DeniseMiller13.00Miller, Denise

  • Status duing execution:
  • Initial state: [B223456789, Rex] RowState: Added
    Version: Original doesn't not exist.
    Version: Current Value: Rex
    Version: Proposed doesn't not exist.
    Version: Default Value: Rex

    BeginLoadData(): turn off notification/constraints/indexing.

    Executing LoadDataRow(...)
    After LoadDataRow: [B223456789, Denise] RowState: Unchanged
    Version: Original Value: Denise
    Version: Current Value: Denise
    Version: Proposed doesn't not exist.
    Version: Default Value: Denise

    EndLoadData(): turn on validation, constraints, etc.

    [B223456789, Denise] RowState: Unchanged
    Version: Original Value: Denise
    Version: Current Value: Denise
    Version: Proposed doesn't not exist.
    Version: Default Value: Denise


Primary key applied, LoadDataRow in conjunction with Begin/EndLoadData, ApplyChanges before BeginLoadData
No error! The last row is updated.

  • Resulted DataTable:
  • EmpIdFirstNameLastNameSalaryLastName and FirstName
    A123456789BettyeWilliams11.00Williams, Bettye
    B223456789DeniseMiller13.00Miller, Denise

  • Status duing execution:
  • Initial state: [B223456789, Rex] RowState: Added
    Version: Original doesn't not exist.
    Version: Current Value: Rex
    Version: Proposed doesn't not exist.
    Version: Default Value: Rex

    Apply AcceptChanges(): [B223456789, Rex] RowState: Unchanged
    Version: Original Value: Rex
    Version: Current Value: Rex
    Version: Proposed doesn't not exist.
    Version: Default Value: Rex

    BeginLoadData(): turn off notification/constraints/indexing.

    Executing LoadDataRow(...)
    After LoadDataRow: [B223456789, Denise] RowState: Unchanged
    Version: Original Value: Denise
    Version: Current Value: Denise
    Version: Proposed doesn't not exist.
    Version: Default Value: Denise

    EndLoadData(): turn on validation, constraints, etc.

    [B223456789, Denise] RowState: Unchanged
    Version: Original Value: Denise
    Version: Current Value: Denise
    Version: Proposed doesn't not exist.
    Version: Default Value: Denise