Tuesday, July 14, 2009

Delete items from List

We should able to do CURD (Create, Update, Read, and Delete) operations in the List. Create, Read, and Update operation are very easy to maintain the List but Delete is difficult because List is automatically rearrange the elements after deleting item[s].

A month ago, we have faced problem while deleting items from List in one of the projects.

Below are steps what we have implemented.
1.Fetch data from SQL.

2.Convert them in to List collection and bind it to GridView having checkbox and paging enabled.
3.From the current page, we need to delete the item
s from List whose rows are checked.

Scenarios while deleting item[s] from List:


A list has object type “Item” having fields “ID” and “ItemName”.

Initial Data:

List Elements – [1,”Item1”], [2,”Item2”], [3,”Item3”], [4,”Item4”], [5,”Item3”], [6,”Item6”]


1. Delete item[s] from list using index.
Deleted List Index – 0, 2
Expected resultant List elements - [2,”Item2”], [4,”Item4”], [5,”Item3”], [6,”Item6”]


1. Data after deleting first item:
List Elements – [2,”Item2”], [3,”Item3”], [4,”Item4”], [5,”Item3”], [6,”Item6”]
2. Data after deleting second item:
List Elements – [2,”Item2”], [3,”Item3”], [5,”Item3”], [6,”Item6”]

Problems:
a. Produces wrong resulting list. b. Some time throws exception - “out of index”.

2. Delete item[s] from list by finding the index of the object and remove the item from the list using searched index.

Delete items having “ItemName”– “Item1”, “Item3”

1. Data after deleting item having ItemName as “Item1”:
  • Search “Item” object using foreach/for/LINQ to find the object having “ItemName” as “Item1”. Either it will give object[s].
  • Find the index of the object using “List.FindIndex” for each founded object.
OR
  • Use method “List.FindAll” which returns array of matching records and then use “List.FindIndex” for matched objects.
  • Delete the object from list using founded index.
In our case, single item found [1,”Item1”] and its index is “0”.

List elements – [2,”Item2”], [3,”Item3”], [4,”Item4”], [5,”Item3”], [6,”Item6”]
2. Data after deleting item having ItemName as “Item3”:
  • Repeat the same process for “Item3”.
In our case, 2 items found [3,”Item3”] and [5,”Item3”] with index is “1” and “3” respectively.

List elements – [2,”Item2”], [3,”Item3”], [4,”Item4”], [5,”Item3”], [6,”Item6”]
Resultant List items – [2,”Item2”], [4,”Item4”], [6,”Item6”]




Problems:
Page 1 elements – [1,”Item1”], [2,”Item2”], [3,”Item3”], Page 2 elements – [4,”Item4”], [5,”Item3”], [6,”Item6”] Because of this method, [3,”Item3”], [5,”Item3”] items are deleted even though you want to delete [3,”Item3”] from Page 1.

This problem gives unexpected results if you have more records having same “ItemName”.


We can also write the logic for preventing the unexpected result.


So, I have written the logic to delete the items in any scenario and achieved the expected result.


Solutions while deleting item[s] from List:

1. Delete item[s] by maintaining the removed items counter.

a. Take variable which stores the number removed items from that list.
int itemsRemoved = 0
b. Calculate the index using that counter and GridView.PageSize and Grid.PageIndex.
int removedIndex = i - itemsRemoved + (gridObject.PageIndex * gridObject.PageSize);
c. Delete the items using above calculated index.
listObject.RemoveAt(removedIndex);
d. Increment that counter by 1 after removing items from that list.
itemsRemoved++;
e. Complete Source:
int itemsRemoved = 0;
List listObject = GetItems();
for (int i = 0; i <>
{
GridViewRow row = gridObject.Rows[i];
CheckBox chkItem = (CheckBox)(row.Cells[0].Controls[1]);
if (chkItem.Checked)
{
int removedIndex = i - itemsRemoved + (gridObject.PageIndex * gridObject.PageSize);
itemsRemoved ++;
listObject.RemoveAt(removedIndex);
}
}
//RefreshGrid again so changes are reflected;

2. Prepare the Deleted Index List.
a. Prepare the index list by checking the checkbox value.
List removeIndexList = new List();
int startIndex = gridObject.PageIndex * gridObject.PageSize;
for (int i = 0; i <>
{
GridViewRow row = gridObject.Rows[i];
CheckBox chkItem = (CheckBox)(row.Cells[0].Controls[1]);
if (chkItem.Checked)
{
removeIndexList.Add(i + startIndex);
}
}
b. Now reverse the list.
removeIndexList.Reverse();
c. Now, using for/foreach delete the item from the list using “List.RemoveAt (index)”.
foreach (int k in indexList)
{
listObject.RemoveAt(k);
}
3. Prepare the Deleted Object List.
a. Prepare the object list by checking the checkbox value.
List deletedItemList = new List();
int startIndex = gridObject.PageIndex * gridObject.PageSize;
for (int i = 0; i <>
{
GridViewRow row = gridObject.Rows[i];
CheckBox chkItem = (CheckBox)(row.Cells[0].Controls[1]);
if (chkItem.Checked)
{
deletedItemList.Add(listObject.ElementAt(startIndex + i));
}
}
b. Now, for each item find the index and delete it from the list using “List.RemoveAt (index)”.

for (int i = 0; i <>
{
int k = listObject.IndexOf(deletedItemList [i]);
if (k > -1)
listObject.RemoveAt(k);
}
4. By nullifying the object.
a. Nullify the object for the selected index
int startIndex = gridObject.PageIndex * gridObject.PageSize;
for (int i = 0; i <>
{
GridViewRow row = gridObject.Rows[i];
CheckBox chkItem = (CheckBox)(row.Cells[0].Controls[1]);
if (chkItem.Checked)
{
listObject[startIndex + i] = null;
}
}
b. Delete all objects whose values are “null”.
listObject.RemoveAll(delegate(Item i) { return i == null; });
5. By modifying the property
a. Select any property whose type is string and insert any special character at first position that has been never occurred in the property. Let’s say ”>“
int startIndex = gridObject.PageIndex * gridObject.PageSize;
for (int i = 0; i <>
{
GridViewRow row = gridObject.Rows[i];
CheckBox chkItem = (CheckBox)(row.Cells[0].Controls[1]);
if (chkItem.Checked)
{
listObject[startIndex + i].Name = ">" + listObject [startIndex + i].Name;
}
}
b. Delete all objects whose property has first character ">".
listObject.RemoveAll(delegate(Item i){return i.Name[0]=='>';});

NOTE:
1. First method gives good performance than others.
2. If you want to display deleted items before removing it then use the Third method.