Note : This post is first published on Nov-2011 in my previous blog Techkindle. Moving the content here.

DataRowState : Its a state corresponding to each row in DataTable.

Consider the following scenario, we have a set of records in DB and from the User Interface we need to provide the facility for user to update any existing records or to add any new records. But, this set of changed records need to send to the DB all at once (i.e for example on a Button Click event), Till that time we need to retain all the records at our page itself. and user also have an option to cancel these changes.
So, while sending all the records to DB at once, we need to find a way to check which row is to be inserted, and which row need to be updated in DB, one option is to maintain one more column in the table as flag, but its very difficult to maintain these flags. another option is to take the advantage of the DataRowState (if we assume records will be maintained in the DataTable). Each row will be having a State (like Added, Unchanged, Modified etc..), using this States we can easily find out which row should be saved and which row should be updated.
DataRowState is very much useful in this kind of scenarios.

First we will look at the different states present in DataRowState,

  • Added The row has been added to a DataRowCollection, and AcceptChanges has not been called.
  • Modified The row has been modified and AcceptChanges has not been called.
  • UnChanged The row has not changed since AcceptChanges was last called.
  • Detached The row has been created but is not part of any DataRowCollection. A DataRow is in this state immediately after it has been created and before it is added to a collection, or if it has been removed from a collection.
  • Deleted The row was deleted using the Delete method of the DataRow.

The below is the example with the all states.

using System;
using System.Data;
namespace DataTableRowState
{
public class BooksList
{
public static void Main(string[] args)
{
//This is the Datatable which contains book records.
DataTable dtBooks = new DataTable();
dtBooks.Columns.Add("Name", typeof(string));
dtBooks.Columns.Add("Id", typeof(Int32));
dtBooks.Columns.Add("Price", typeof(decimal));
//Taking Id as a primary key column and setting it to AutoIncrement.
dtBooks.PrimaryKey = new DataColumn[] { (dtBooks.Columns["Id"]) };
dtBooks.Columns["Id"].AutoIncrement = true;
dtBooks.Columns["Id"].AutoIncrementSeed = 1;//This is the initial primary key value
dtBooks.Columns["Id"].AutoIncrementStep = 1;//This is the incremeted value.
//Inserting Records.
DataRow drBook1 = dtBooks.NewRow();
drBook1["Name"] = "The Last Lecture";
drBook1["Price"] = 299;
dtBooks.Rows.Add(drBook1);
DataRow drBook2 = dtBooks.NewRow();
drBook2["Name"] = "Leader who had no title";
drBook2["Price"] = 199;
dtBooks.Rows.Add(drBook2);
DataRow drBook3 = dtBooks.NewRow();
drBook3["Name"] = "The Roots";
drBook3["Price"] = 599;
dtBooks.Rows.Add(drBook3);
DataRow drBook4 = dtBooks.NewRow();
drBook4["Name"] = "The Secret";
drBook4["Price"] = 500;
dtBooks.Rows.Add(drBook4);
DataRow drBook5 = dtBooks.NewRow();
drBook5["Name"] = "Tuesdays with Moorie";
drBook5["Price"] = 250;
dtBooks.Rows.Add(drBook5);
Console.WriteLine("==== Initial Book List ==== \n");
Console.WriteLine("ID\tPRICE \t NAME");
Console.WriteLine("———————————————");
for (int i = 0; i < dtBooks.Rows.Count; i++)
{
Console.WriteLine(dtBooks.Rows[i]["Id"].ToString() + "\t"
+ dtBooks.Rows[i]["Price"].ToString() + "\t "
+ dtBooks.Rows[i]["Name"].ToString());
}
Console.WriteLine("\n");
Console.ReadLine();
//Commits all the changes made to this table since the last time AcceptChanges was called.
//Here all the previously added rows state will be changed from Added to Unchanged.
dtBooks.AcceptChanges();
//Modified Row.
dtBooks.Rows[0]["Name"] = "The Last Lecture By Raundy Paush";
dtBooks.Rows[0]["Price"] = 499;
//Added Row.
DataRow drBook6 = dtBooks.NewRow();
drBook6["Name"] = "A Better India A Better World";
drBook6["Price"] = 399;
dtBooks.Rows.Add(drBook6);
Console.WriteLine("==== Book List After Changes ==== \n");
Console.WriteLine("ID\tPRICE \t NAME");
Console.WriteLine("———————————————");
for (int i = 0; i < dtBooks.Rows.Count; i++)
{
Console.WriteLine(dtBooks.Rows[i]["Id"].ToString() + "\t"
+ dtBooks.Rows[i]["Price"].ToString() + "\t "
+ dtBooks.Rows[i]["Name"].ToString());
}
Console.WriteLine("\n");
Console.ReadLine();
DataTable dtAdded = dtBooks.GetChanges(DataRowState.Added);
if (dtAdded != null)
{
Console.WriteLine("==== Newly Added Books in the Book List==== \n");
Console.WriteLine("ID\tPRICE \t NAME");
Console.WriteLine("———————————————");
for (int rowIndex = 0; rowIndex < dtAdded.Rows.Count; rowIndex++)
{
Console.WriteLine(dtAdded.Rows[rowIndex]["Id"].ToString() + "\t"
+ dtAdded.Rows[rowIndex]["Price"].ToString() + "\t "
+ dtAdded.Rows[rowIndex]["Name"].ToString());
}
Console.WriteLine("\n");
}
Console.ReadLine();
DataTable dtModified = dtBooks.GetChanges(DataRowState.Modified);
if (dtModified != null)
{
Console.WriteLine("==== Modified Books in the Book List ==== \n");
Console.WriteLine("ID\tPRICE \t NAME");
Console.WriteLine("———————————————");
for (int rowIndex = 0; rowIndex < dtModified.Rows.Count; rowIndex++)
{
Console.WriteLine(dtModified.Rows[rowIndex]["Id"].ToString() + "\t"
+ dtModified.Rows[rowIndex]["Price"].ToString() + "\t "
+ dtModified.Rows[rowIndex]["Name"].ToString());
}
Console.WriteLine("\n");
}
Console.ReadLine();
DataTable dtUnChanged = dtBooks.GetChanges(DataRowState.Unchanged);
if (dtUnChanged != null)
{
Console.WriteLine("==== UnChanged Books in the Book List ==== \n");
Console.WriteLine("ID\tPRICE \t NAME");
Console.WriteLine("———————————————");
for (int rowIndex = 0; rowIndex < dtUnChanged.Rows.Count; rowIndex++)
{
Console.WriteLine(dtUnChanged.Rows[rowIndex]["Id"].ToString() + "\t"
+ dtUnChanged.Rows[rowIndex]["Price"].ToString() + "\t "
+ dtUnChanged.Rows[rowIndex]["Name"].ToString());
}
Console.WriteLine("\n");
}
Console.ReadLine();
//In this case we can not access the deleted rows, so we are printing it first and then deleting.
Console.WriteLine("==== Deleted Books in the Book List ==== \n");
Console.WriteLine("ID\tPRICE \t NAME");
Console.WriteLine("———————————————");
Console.WriteLine(drBook2["Id"].ToString() + "\t"
+ drBook2["Price"].ToString() + "\t "
+ drBook2["Name"].ToString());
dtBooks.Rows[1].Delete();
Console.WriteLine("\n");
Console.ReadLine();
//In this case we can not access the removed rows, so we are printing it first and then removing.
Console.WriteLine("==== Detached Books in the Book List ==== \n");
Console.WriteLine("ID\tPRICE \t NAME");
Console.WriteLine("———————————————");
Console.WriteLine(drBook5["Id"].ToString() + "\t" + drBook5["Price"].ToString() + "\t " + drBook5["Name"].ToString());
dtBooks.Rows.Remove(drBook5);
Console.WriteLine("\n");
Console.ReadLine();
Console.WriteLine("==== Book List After Rejecting all the changes ==== \n");
Console.WriteLine("ID\tPRICE \t NAME");
Console.WriteLine("———————————————");
dtBooks.RejectChanges();
for (int i = 0; i < dtBooks.Rows.Count; i++)
{
Console.WriteLine(dtBooks.Rows[i]["Id"].ToString() + "\t"
+ dtBooks.Rows[i]["Price"].ToString() + "\t "
+ dtBooks.Rows[i]["Name"].ToString());
}
Console.WriteLine("\n");
Console.ReadLine();
}
}
}

view raw
DataRowState
hosted with ❤ by GitHub

The output will be as follows:

In the above output we can see that , at last the changes are canceled, but still one of the row is not exist.this is because it has got removed(not deleted).we cannot get the records back once we use Remove. but if we use Delete, still we can get our records back.

Happy Learning 🙂