C# Collection was modified; enumeration operation may not execute [duplicate] - c#

This question already has answers here:
How do I loop through items in a list box and then remove those item?
(8 answers)
Closed 9 years ago.
List<String> employeeTimings;
public string[] sTime = {"0000", "0030", "0100", "0130", "0200", "0230", "0300", "0330", "0400", "0430", "0500", "0530", "0600", "0630", "0700", "0730", "0800", "0830", "0900", "0930", "1000", "1030", "1100", "1130", "1200",
"1230", "1300", "1330", "1400", "1430", "1500", "1530", "1600", "1630", "1700", "1730", "1800", "1830", "1900", "1930", "2000", "2030", "2100", "2130", "2200", "2230", "2300", "2330"};
employeeTimings = new List<String>(sTime);
int i=0;
DataTable dt = new DataTable();
dt.Columns.Add(new DataColumn("Location", typeof(string)));
dt.Columns.Add(new DataColumn("Station", typeof(string)));
foreach (DataColumn dc in dt.Columns)
{
dt.Columns.Add(employeeTimings[i], typeof(string));
i++;
}
SchedulingTableDGV.DataSource = dt;
i get an error "Collection was modified; enumeration operation may not execute." how can i solve this?

You cannot add or remove from the collection you are iterating with a foreach. You need to perform adding or removing actions outside of the foreach.
foreach (DataColumn dc in dt.Columns)
{
dt.Columns.Add(employeeTimings[i], typeof(string)); // Problem.
i++;
}
Try this:
foreach (var timing in employeeTimings)
{
dt.Columns.Add(timing, typeof(string));
}

You can't modify a collection you are looping over with foreach. The solution in your case is pretty simple: Since you do not use dc inside the loop, why not use a normal for loop, like:
int length = dt.Columns.Length;
for (int i = 0; i < length; i++)
{
dt.Columns.Add(employeeTimings[i], typeof(string));
}

With LINQ you can do:
foreach (DataColumn dc in dt.Columns.OfType<DataColumn>().ToArray())
{
dt.Columns.Add(employeeTimings[i], typeof(string));
i++;
}

You are modifying the collection dt.Columns with the Add method while you are iterating over it:
foreach (DataColumn dc in dt.Columns)
{
dt.Columns.Add(employeeTimings[i], typeof(string));
i++;
}
Apart from not adding all timing strings this modifies the collection you are adding the columns to.
You should enumerate employeeTimings and add the columns like:
foreach(string s in employeeTimings)
{
dt.Columns.Add(s, typeof(string));
}

I guess your true intentions are to add the full employeeTimings list to the datatable columns
If this is right then you should loop on the list not on the columns
foreach (string s in employeeTimings)
dt.Columns.Add(s, typeof(string));

Related

populate datatable with arrays of strings

How do i populate this dataTable with array of strings? Im using this template but i can only add data hardcoded... I have an string[]values which contains my data and that should be added to the datatable. I think its quite easy but i don't see it. i've been trying to loop through it but that doens't seem to work? Think im missing a crucial step.
I've created a my datatable here :
DataTable dt = new DataTable() { TableName = "MBR" };
Adding the columns to it
string[] columns = new string [l];
for (int i = 0; i < l; i++)
{
columns[i] = tags[i];
}
for (int i = 0; i < timeStamps.Count(); i++)
{
foreach (var item in tagCollection)
{
if (timeStamps[i].Date == item.time)
{
Console.WriteLine(item.time + " " + item.name );
}
}
}
dt.Columns.AddRange(columns.Select(c => new DataColumn(c.ToString())).ToArray());
And this i used in the template my collegue is working with and we need to provide the data here
var rows = new string[][]
{
new string[] {"1", "2", "false" },
new string[] { "test", "10000", "19.9" },
};
foreach (var row in rows)
{
dt.Rows.Add(row);
}
//Convert datatable to dataset and add it to the workbook as worksheet
ds.Tables.Add(dt);
workbook.Worksheets.Add(ds);
I've got many columns like 500+. And i need to add to each column a piece of data which i get from my string[]. which can contains 10 or 500+ records it depends. I need to add each record to a row. My columns are already working in this thing. I just need a way to add multiple Arrays to the table
This works for me:
DataTable dt = new DataTable() { TableName = "MBR" };
dt.Columns.Add(new DataColumn("A", typeof(string)));
dt.Columns.Add(new DataColumn("B", typeof(string)));
dt.Columns.Add(new DataColumn("C", typeof(string)));
var rows = new string[][]
{
new string[] {"1", "2", "false" },
new string[] { "test", "10000", "19.9" },
};
foreach (var row in rows)
{
dt.Rows.Add(row);
}
That gives me:
Here's how you might fill a datatable from a file of people:
var people = new DataTable();
people.Columns.Add("Name");//string
people.Columns.Add("Age", typeof(int));
people.Columns.Add("HireDate", typeof(DateTime));
people.Columns.Add("IsManager", typeof(bool));
foreach(var line in File.ReadLines("people.csv")){
var bits = line.Split(',');
dt.Rows.Add(new object[]{
bits[0], //Name
int.Parse(bits[1]), //Age
DateTime.Parse(bits[2]), //HireDate
bool.Parse(bits[3]) //IsManager
});
}
It would, of course, be preferable to use some library like Csvhelper if you're reading from a CSV - it can read into DataTables directly and is a lot more sophisticated than this example. This is just to show the process of "make a datatable, add columns, add rows by providing values for columns"
It would be better to create a strongly typed datatable for this:
Add a new DataSet type of file to your project and goive it a good name
Open it, right click the surface, choose Add DataTable, give it a sensible name
Right click the table, choose Add Column .. add a column and set its name, data type, default value etc...
Repeat until all columns are done
Using this in your code is mostly the same as above, except you make an instance of the table. It is an inner class so you create it using the name of the dataset too:
var dt = new YourDataSetNameHere.YourDataTableNameHere_DataTable();
//the columns are already added, you don't need to add them
foreach(var line in ...){
...
dt.Add_YourDataTableNameHere_Row(
bits[0], //Name
int.Parse(bits[1]), //Age
DateTime.Parse(bits[2]), //HireDate
bool.Parse(bits[3]) //IsManager
);
}
They're a lot nicer to use than regular weakly typed datatables

C# KeyValue foreach column in row

I am here today trying to work out how I can do this. I have the code below to look through each column in a DataRow, but how can I access the key AND value? I want to assign it to a dictionary in the class but I can't seem to get both of them, the only way I can get anything is by calling:
var columnValue = playerDataRow[column];
Here is the full thing:
using (var mysqlConnection = Sirius.GetServer().GetDatabaseManager().GetConnection())
{
mysqlConnection.SetQuery("SELECT * FROM `users` WHERE `auth_ticket` = #authTicket LIMIT 1");
mysqlConnection.AddParameter("authTicket", authTicket);
var playerDataTable = mysqlConnection.GetTable();
foreach (DataRow playerDataRow in playerDataTable.Rows)
{
foreach (DataColumn column in playerDataTable.Columns)
{
var columnValue = playerDataRow[column];
}
}
}
foreach (DataRow playerDataRow in playerDataTable.Rows)
{
var myDic = new Dictionary<string, object>();
foreach (DataColumn column in playerDataTable.Columns)
{
myDic.Add(column.ColumnName, playerDataRow[column]);
}
}
the variable column will be the key and the value will be columnValue
looks that you only want one row of output - perhaps for this specific user based on auth_ticket
here is an example of how to get all values for this row into a Dictionary of strings (I'm converting all data to strings by the way just for this example)
var htRowValues = new Dictionary<string,string>();
using (var mysqlConnection = Sirius.GetServer().GetDatabaseManager().GetConnection())
{
mysqlConnection.SetQuery("SELECT * FROM `users` WHERE `auth_ticket` = #authTicket LIMIT 1");
mysqlConnection.AddParameter("authTicket", authTicket);
var playerDataTable = mysqlConnection.GetTable();
foreach (DataRow playerDataRow in playerDataTable.Rows)
{
foreach (DataColumn column in playerDataTable.Columns)
{
var columnValue = playerDataRow[column];
htRowValues[column.ColumnName]=System.Convert.ToString(columnValue);
}
}
}
now you have all column values in the dictionary for this one row of data.

Brackets To each Line of Data in a foreach loop

My problem is that i have a foreach loop that saves every row of data into a List and then creates a TXT from the list, the problem is that my data is saved into the TXT in this form:
["ROW1","DATA1","DATA2","DATA3","ROW2","DATA4","DATA5","DATA6"]
And i want to make my txt to have the data like this:
[["ROW1","DATA1","DATA2","DATA3"],["ROW2","DATA4","DATA5","DATA6"]]
Getting each row into a separate aditional brackets brackets("[]"), how can i do this without using another List?
This is my Foreach Loop:
List<string> listaprocedure = new List<string>();
foreach (DataRow dato in myTable.Rows)
{
foreach (DataColumn datoC in myTable.Columns)
{
listaprocedure.Add(dato[datoC].ToString());
}
}
json4 = JsonConvert.SerializeObject(procedimiento2);
System.IO.File.WriteAllText(#"C:\procedure.txt", json4);
You can manually iterate through rows, writing each one as you have read it, then add , after it (except last row). Plus add [ and ] at the beginning and end.
Quite ugly, but can help if you deal with really big table.
But the best option is to populate List<List<string>> (or string[,]).
Anyway here is working example:
using (var reader = File.CreateText("C:\\procedure.txt"))
{
// Starting outer json array
reader.WriteLine("[");
for (var rowIndex = 0; rowIndex < myTable.Rows.Count; rowIndex++)
{
var row = myTable.Rows[rowIndex];
var rowValues = new List<string>(); // can be reused if needed
foreach (DataColumn column in myTable.Columns)
rowValues.Add(row[column].ToString());
var jsonRow = JsonConvert.SerializeObject(rowValues);
// Write current row
reader.Write(jsonRow);
// Add separating comma
if (rowIndex != myTable.Rows.Count - 1)
reader.WriteLine(",");
}
// End outer json array
reader.WriteLine("]");
}
Given your sample data, this works:
var query =
from dr in myTable.Rows.OfType<DataRow>()
from dc in myTable.Columns.OfType<DataColumn>()
group dr[dc].ToString() by dc.Ordinal / 4;
var json4 = JsonConvert.SerializeObject(query);
This gives me:
[["ROW1","DATA1","DATA2","DATA3"],["ROW2","DATA4","DATA5","DATA6"]]
I used this code to initialize my data:
var myTable = new DataTable();
myTable.Columns.Add("A1", typeof(string));
myTable.Columns.Add("A2", typeof(string));
myTable.Columns.Add("A3", typeof(string));
myTable.Columns.Add("A4", typeof(string));
myTable.Columns.Add("B1", typeof(string));
myTable.Columns.Add("B2", typeof(string));
myTable.Columns.Add("B3", typeof(string));
myTable.Columns.Add("B4", typeof(string));
myTable.Rows.Add("ROW1", "DATA1", "DATA2", "DATA3", "ROW2", "DATA4", "DATA5", "DATA6");

Add a Generic List/Enumerable DataRow to DataTable?

I am trying to write a function which takes generic List/Enumerable and add DataRow to existing DataTable but only for Custom Columns.
public void AddGridRow<T>(IEnumerable<T> rowData, params String[] columnNames)
{
HashSet<String> columnsHashSet = new HashSet<String>(columnNames);
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T));
foreach (T item in rowData)
{
foreach (PropertyDescriptor prop in properties)
{
foreach (DataColumn column in _dataGridTable.Columns)
{
DataRow newRow = _dataGridTable.NewRow();
if (columnsHashSet.Contains(prop.Name))
{
newRow[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
_dataGridTable.Rows.Add(newRow); // _dataGridTable is my existing DataTable
break;
}
}
}
}
}
Now the problem is it is not behaving correctly, lets say I have to add 1 row in 4 columns (columnNames), it is adding the 1 Row per columns. Also there are far many foreach loops.
How can I correct this and if possible optimize it.
You need to move the "_dataGridTable.Rows.Add(newRow);" line outside of the inner foreach loop:
foreach (T item in rowData)
{
foreach (PropertyDescriptor prop in properties)
{
DataRow newRow = _dataGridTable.NewRow();
foreach (DataColumn column in _dataGridTable.Columns)
{
if (columnsHashSet.Contains(prop.Name))
{
newRow[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
break;
}
}
}
_dataGridTable.Rows.Add(newRow); // _dataGridTable is my existing DataTable
}

Rename column and type in Datatable after data is loaded

I am importing data from csv file, sometimes there are column headers and some times not the customer chooses custom columns(from multiple drop downs)
my problem is I am able to change the columns type and name but when I want to import data row into cloned table it just adds rows but no data with in those rows. If I rename the column to old values it works, let's say column 0 name is 0 if I change that to something else which I need to it won't fill the row below with data but If I change zero to zero again it will any idea:
here is my coding:
#region Manipulate headers
DataTable tblCloned = new DataTable();
tblCloned = tblDataTable.Clone();
int i = 0;
foreach (string item in lstRecord)
{
if (item != "Date")
{
var m = tblDataTable.Columns[i].DataType;
tblCloned.Columns[i].DataType = typeof(System.String);
tblCloned.Columns[i].ColumnName = item;
}
else if(item == "Date")
{
//get the proper date format
//FillDateFormatToColumn(tblCloned);
tblCloned.Columns[i].DataType = typeof(DateTime);
tblCloned.Columns[i].ColumnName = item;
}
i++;
}
tblCloned.AcceptChanges();
foreach (DataRow row in tblDataTable.Rows)
{
tblCloned.ImportRow(row);
}
tblCloned.AcceptChanges();
#endregion
in the second foreach loop when it calls to import data to cloned table it adds empty rows.
After couple of tries I came up with this solution which is working:
foreach (DataRow row in tblDataTable.Rows)
{
int x = 0;
DataRow dr = tblCloned.NewRow();
foreach (DataColumn dt in tblCloned.Columns)
{
dr[x] = row[x];
x++;
}
tblCloned.Rows.Add(dr);
//tblCloned.ImportRow(row);
}
but I will accept Scottie's answer because it is less code after all.
Instead of
foreach (DataRow row in tblDataTable.Rows)
{
tblCloned.ImportRow(row);
}
try
foreach (DataRow row in tblDataTable.Rows)
{
tblCloned.LoadDataRow(row.ItemArray, true);
}

Categories

Resources