collection was modified enumeration operation might not execute - c#

string field = ViewState["Field"].ToString();
DataTable dt = (DataTable)Session["Academic"];
foreach (DataRow dr in dt.Rows)
{
if (dr["Degree"].ToString() == field)
{
dr.Delete();
dt.AcceptChanges();
}
}
Session["Academic"] = dt;
gdvwAcademic1.DataSource = Session["Academic"] as DataTable;
gdvwAcademic1.DataBind();
when this code executed raise error as "collection was modified enumeration operation might not execute." why this so..?

You cannot modify a collection in a foreach. Try this as an alternative to apomene's answer (Pretty much does the same thing, except using the remove method of a list instead of indexes.
List<DataRow> toDelete = new List<DataRow>();
foreach(DataRow dr in dt.Rows){
if(dr["Degree"].ToString() == field){
toDelete.Add(dr);
}
}
foreach (DataRow dr in toDelete){
dt.Rows.Remove(dr);
}
This should solve your problem.

You can't modify the collection in a foreach. So don't delete or add things in it.
You could prevent this error by creating a new collection with items you want to modify, for example with LINQ (the ToList() is essential):
var toDelete = dt.AsEnumerable().Where(r => r["Degree"].ToString() == field).ToList();
Now you can loop this without a problem.
foreach(DataRow rowToDelete in toDelete)
rowToDelete.Delete();
dt.AcceptChanges(); // you could do that also in the loop now

you cant delete inside foreach use for loop or make a delete List:
List <int> toBeDel=new List<int>();
foreach (DataRow dr in dt.Rows)
{
if (dr["Degree"].ToString() == field)
{
toBEDel.Add(indexOf(dr));
}
}
foreach (int i in toBeDel)
{
dt.Rows[i].Delete();
}

for (int i = 0;i < dt.Rows.Count; i++)
{
DataRow dr = dt.Rows[i];
if (dr["Degree"].ToString() == field)
{
dr.Delete();
i-=1;
}
}
dt.AcceptChanges();
you can use this, one loop.
For any people find this post.

Related

Looping through 2 datatable and adding values to third

I have created 3 datatables
var dt1= new DataTable();
var dt2= new DataTable();
var dt3= new DataTable();
Then i loop
foreach (DataRow row1 in dt1.Rows)
{
dt3.Rows.Add(row1.ItemArray);
foreach (DataRow row2 in dt2.Rows)
{
var Id2 = row1["Id"];
var Id1= row2["Id"];
if (Id1 == Id2)
{
dt3.rows["Name"] = "" ; // doesnt work
}
}
}
As you can see that i loop on 2 datatables. Then in inner loop i check if the records matches. Now if the record matches then i want to update column "Name" on dt3 datatable.
I tried using
dt3.rows["Name"] = "" ;
But this doesnt work. I know the reason that its because i again need to loop on dt3 datatable and
assign values to column in that loop. But not sure how to do it and if there is even more better solution. I mean we can find id in dt3 datatable and then update value. But not sure how to do it
Is there more intelligent solution than looping on 2 table?
The first foreach is not needed. A simple DataTable.Copy will bring all the data and structure from the original table in the destination table. Then looping on the second table and Select on the third to find the matching rows and clear the name.
dt3 = dt1.Copy();
foreach (DataRow row2 in dt2.Rows)
{
DataRow[] match = dt3.Select("ID=" + row2["ID"].ToString());
if(match.Lenght > 0)
match[0]["Name"] = "" ;
}
Not sure if this is more performant from the other answers. Need to be tested
dt3.rows doesn't work, you want to change the name of the row that you have added now. This should work:
foreach (DataRow row1 in dt1.Rows)
{
DataRow newRow = dt3.Rows.Add(row1.ItemArray);
foreach (DataRow row2 in dt2.Rows)
{
var Id2 = row1["Id"];
var Id1 = row2["Id"];
if (Id1 == Id2)
{
newRow["Name"] = "new Name";
}
}
}
Try this:
foreach (DataRow row1 in dt1.Rows)
{
var row = dt3.Rows.Add(row1.ItemArray);
foreach (DataRow row2 in dt2.Rows)
{
var Id2 = row1["Id"];
var Id1= row2["Id"];
if (Id1 == Id2)
{
row["Name"] = ""; //maybe works
}
}
}
How about,
dt2Lookup = new HashSet(
dt2.AsEnumerable().Select(row => row.Field<int>("Id")));
dt3 = dt1.Clone();
forreach (var row In dt1.AsEnumerable())
{
var newRow = dt3.Rows.Add(row.ItemArray)
if (dt2lookup.Contains(row.Field<int>("Id"))
{
newRow.SetField("Name", string.Empty);
}
}
The HashSet should provide good lookup performance.
dt3 = dt1.Copy();
var RowDictionary = dt3.Rows.OfType<DataRow>().ToDictionary(dr => dr["ID"].ToString());
//replace by Dictionary<string,List<DataRow>> in case ID is not unique and fill it with a foreach loop.
foreach (DataRow row2 in dt2.Rows)
{
DataRow Match;
if (c.TryGetValue(row2["ID"].ToString(), out Match))
{
Match["Name"] = "";
}
}
You should call:
dt3.rows[dt3.rows.Count - 1].Columns["Name"] = "" ;

Looping through a DataTable

Well. I have a DataTable with multiple columns and multiple rows.
I want to loop through the DataTable dynamically basically the output should look as follows excluding the braces :
Name (DataColumn)
Tom (DataRow)
Peter (DataRow)
Surname (DataColumn)
Smith (DataRow)
Brown (DataRow)
foreach (DataColumn col in rightsTable.Columns)
{
foreach (DataRow row in rightsTable.Rows)
{
//output
}
}
I typed that out and noticed this would not work. Can someone please advice on a better way of doing this?
foreach (DataColumn col in rightsTable.Columns)
{
foreach (DataRow row in rightsTable.Rows)
{
Console.WriteLine(row[col.ColumnName].ToString());
}
}
foreach (DataRow row in dt.Rows)
{
foreach (DataColumn col in dt.Columns)
Console.WriteLine(row[col]);
}
Please try the following code below:
//Here I am using a reader object to fetch data from database, along with sqlcommand onject (cmd).
//Once the data is loaded to the Datatable object (datatable) you can loop through it using the datatable.rows.count prop.
using (reader = cmd.ExecuteReader())
{
// Load the Data table object
dataTable.Load(reader);
if (dataTable.Rows.Count > 0)
{
DataColumn col = dataTable.Columns["YourColumnName"];
foreach (DataRow row in dataTable.Rows)
{
strJsonData = row[col].ToString();
}
}
}
If you want to change the contents of each and every cell in a datatable then we need to Create another Datatable and bind it as follows using "Import Row". If we don't create another table it will throw an Exception saying "Collection was Modified".
Consider the following code.
//New Datatable created which will have updated cells
DataTable dtUpdated = new DataTable();
//This gives similar schema to the new datatable
dtUpdated = dtReports.Clone();
foreach (DataRow row in dtReports.Rows)
{
for (int i = 0; i < dtReports.Columns.Count; i++)
{
string oldVal = row[i].ToString();
string newVal = "{"+oldVal;
row[i] = newVal;
}
dtUpdated.ImportRow(row);
}
This will have all the cells preceding with Paranthesis({)

DataTable - foreach Row, EXCEPT FIRST ONE

I am using a DataTable for some calculations in my app. I need to do the iterate trough all the rows except the first one. Is it possible?
Something like:
DataTable dt;
foreach (DataRow r in dt.Rows /*EXCEPT THE FIRST ONE*/)
{
//do something...
}
LINQ is your friend:
DataTable dt;
foreach (DataRow r in dt.Rows.Cast<DataRow>().Skip(1))
{
//do something...
}
The call to Cast() is required here since DataTable.Rows implements the non-generic IEnumerable, and linq's extension methods are only available for IEnumerable<T>
You also have another option:
DataTable dt;
foreach (DataRow r in dt.AsEnumerable().Skip(1))
{
//do something...
}
Ok you got your answers but in case you donT want to use linq. Check the index of the row in the table:
foreach (DataRow row in m_dtMatrix.Rows)
{
if (m_dtMatrix.Rows.IndexOf(row) != 0)
{
...
}
}
Here's a quick and dirty
DataTable dt;
bool isFirst = true;
foreach (DataRow r in dt.Rows /*EXCEPT THE FIRST ONE*/)
{
if( isFirst ) {
isFirst = false;
continue;
}
//do something...
}

Skip a row in a for each rowset loop in c#

I am looping through a dataset for each data row
foreach (DataRow DRow in ds.Tables[0].Rows)
I would like to jump the current row when ever a if statement is true.
Any clue how to do it?
Thanks in advance !
Use continue:
foreach (DataRow DRow in ds.Tables[0].Rows)
{
if(expression)
continue;
}
continue skips the remaining part of the foreach block for the current element an continues at the next new element in your collection.
Try this:
foreach (DataRow DRow in ds.Tables[0].Rows)
{
if(true) // escape condition met
continue;
}
You are looking for the continue keyword...
foreach (DataRow DRow in ds.Tables[0].Rows) {
if(condition)
continue;
}
The continue; instruction tells a loop to skip the rest of the code and move to the next iteration.
foreach (DataRow DRow in ds.Tables[0].Rows)
{
if (--condition here--) continue;
}

Make a copy of a Datatable with some changes

I am trying to make a copy of a DataTable dt1 to a new one dt2.
dt1 contains columns of string and boolean types.
dt2 will contains only string types.
The following is my code which works fine.
public DataTable Convert(DataTable dt1)
{
try
{
var dt2 = dt1.Clone();
foreach (DataColumn dc in dt2.Columns)
{
dc.DataType = Type.GetType("System.String");
}
foreach (DataRow row in dt1.Rows)
{
dt2.ImportRow(row);
}
foreach (DataRow dr in dt2.Rows)
{
foreach (DataColumn dc in dt2.Columns)
{
bool value;
if (bool.TryParse(dr[dc].ToString(), out value))
{
dr[dc] = "+";
}
}
}
return dt2;
}
finally
{
}
}
1st step: Clone of dt1 and change the columns types to string.
2nd step: Import the rows from dt1 to dt2
3rd step: Change all true values to "+"
Is there a better way to perform those steps. "better" mean clearer, simpler, less code, less steps, better performance.
The code you've provided very clearly describes your intent and is succinct. We can however make some optimizations that will help with performance.
You are attempting to parse every field of every row instead of determining which fields actually require manipulation. As the number of non-boolean columns increases you're doing more work than is needed.
You already have the original table which contains bool values so you could do away with parsing all together.
Here is a version that optimizes around these two points. The code is not shorter or more elegant, but it will require no text parsing and far fewer evaluations.
public DataTable Convert2(DataTable dt1)
{
DataTable dt2 = dt1.Clone();
// Alter all columns datatype
foreach (DataColumn col in dt2.Columns)
col.DataType = typeof(string);
// Import all rows from existing table
foreach (DataRow row in dt1.Rows)
dt2.ImportRow(row);
// Index the boolean columns that will require evaluation
List<int> booleans = new List<int>();
foreach (DataColumn col in dt1.Columns)
{
if (col.DataType == typeof(bool))
booleans.Add(col.Ordinal);
}
// Since two tables will be identical except for datatypes
// iterate over original table and cast instead of performing
// a string conversion and parsing the result.
for (int row = 0; row < dt1.Rows.Count; row++)
{
foreach (int index in booleans)
{
if ((bool) dt1.Rows[row][index])
dt2.Rows[row][index] = "+";
}
}
return dt2;
}
Additionally, I left out the try..finally block since you're not using it.
That code would do the job.
public DataTable Convert(DataTable dt1)
{
try
{
var dt2 = dt1.Clone();
foreach (DataColumn dc in dt2.Columns)
{
dc.DataType = Type.GetType("System.String");
}
foreach (DataRow row in dt1.Rows)
{
dt2.ImportRow(row);
DataRow dr = dt2.Rows[dt2.Rows.Count-1]
foreach (DataColumn dc in dt2.Columns)
{
bool value;
if (bool.TryParse(dr[dc].ToString(), out value))
{
dr[dc] = "+";
}
}
}
return dt2;
}
finally
{
}
}

Categories

Resources