Looping through data table to get value - c#

I have a DataTable with multiple rows. I'm using a foreach loop to loop through each item and return the name. This is returning the same (1st) value for each row. What have I done wrong?
DataTable table = new DataTable();
table.Columns.Add("tag", typeof(string));
string name = hfSelected.Value;
string[] names = name.Split(',');
for (int i = 0; i < names.Length; i++)
table.Rows.Add(new object[] { names[i] });
DataRow row = table.Rows[0];
foreach (var item in table.Rows)
{
Value = row["tag"].ToString() // this is returning the same value for both items in the table.
}

In a comment you mentioned that you get the error:
cannot apply indexing with [] to an expression of type object
when trying to access item["tag"] in the foreach loop.
You need to explicitly declare the DataRow in the foreach.
// declare DataRow here, not var
foreach (DataRow item in table.Rows)
{
// use item here
Value = item["tag"].ToString(); // use += to concatenate string
}
The reason is that the DataRowCollection implements a non-generic IEnumerable so you index an object instead of DataRow. The solution above casts to a DataRow.
I would recommend looking at the Field<T>() and AsEnumerable() methods from System.Data.DataSetExtensions. AsEnumerable() returns an IEnumerable<DataRow>. Field() provides strongly typed access to the values (ie it casts/converts the types for you).
Then you can do:
foreach (var item in table.AsEnumerable())
{
// item is a DataRow here
var myString = item.Field<string>("tag"); // gets string
// you can also do
var myInt = item.Field<int>("Id"); // gets int
var myDate = item.Field<DateTime?>("Date"); // gets nullable DateTime?
var myValue = item.Field<decimal>("Price"); // gets decimal
}

Carl is correct, this is producing the same output, because inside the iteration, you use the same row, all the time. You should use 'item', instead of 'row' there (you don't need 'row' at all).
The exception you receive is because you declared 'item' with a dynamic type, it's
foreach (var item in table.Rows)
You can try
foreach (DataRow item in table.Rows)
this way, you'll be able to get the column info.

your iteration seems to be using the same 'row' variable instead of the 'item' variable you defined in the foreach statement.

Related

How do Index an Array of type IEnumerable<Data Row>?

I want to index an Array of IEnumerable<DataRow> and print out the Data into a table. I get the below error and I'm not sure hoe to overcome it.
cannot convert type System.Data.DataRow to string
IEnumerable<DataRow> query = from result in
DtSet.Tables["Results"].AsEnumerable()
where result.Field<string
("test").Contains("50")
select result;
var queryArray = query.ToArray();`
for (int i = 0; i < queryArray.Count(); i++)
{
table.Rows[i + 1].Cells[0].Paragraphs.First().Append(queryArray[i]);
}
Consider:
var queryArray = query.ToArray();
(You also have a small problem in that you're trying to stuff a datarow into your destination paragraph; this might just append "system.data.datarow" to your paragraph)
But really you could just delete that line and:
int i = 1:
foreach(var q in query)
table.Rows[i++].Cells[0].Paragraphs.First().Append(q["your column name"].ToString());
That is to say; enumerate the IEnumerable, using a separate indexer variable to keep track of where you are in (the excel sheet?)
Side note; I put a call into extract a single column from the data row; you could alternatively make this a part of your select LINQ statement, converting the datarow to a string enuneabke instead
It looks like using a dataview rowfilter might save you some effort here, something like:
DataView dv = new DataView(DtSet.Tables["Results"]);
dv.RowFilter = "test LIKE '%50%'";
foreach (DataRowView drv in dv)
{
//do the stuff...
}
Microsoft Documentation

Targeting a specific column in a DataRow

I'm trying to perform the C# equivalent of Select * where [columnname] = [value]. I began with a foreach loop to iterate through the table row by row, however I had forgotten that one cannot access a column via row.column["<colname>"].
How do I achieve this objective? Most of the examples I have seen target one specific row with the intention of casting it's value to a string, however my task is to move all entries with a value of DateTime == < DateTime.Today to an archived table.
Can I continue with the following code? Or am I approaching this in the wrong manner?
void archiveDates()
{
foreach (DataRow row in workingupdates.storageTable.Rows)
{
//target DateTime column here
}
}
You can use the Field extension method that is strongly typed and also supports nullable types. You have an overload for the index, name or the DataColumn(among others):
foreach (DataRow row in workingupdates.storageTable.Rows)
{
DateTime dt = row.Field<DateTime>("columnname");
}
If you instead want to find all rows where the date column has a specific value you can use Linq-To-DataTable:
var matchingDataRows = workingupdates.storageTable.AsEnumerable()
.Where(row => row.Field<DateTime>("columnname") == dateTimeVariable);
Now you can simply enumerate this query:
foreach (DataRow row in matchingDataRows)
{
// ...
}
Or create a collection like
a DataRow[] with matchingDataRows.ToArray() or
a List<DataRow> with matchingDataRows.ToList()
a new DataTable with matchingDataRows.CopyToDataTable()
Note that you have to add System.Linq; to the top of the file.

How to access to the content of a DataRow?

I have the following problem.
I have a DataTAble object that represent a single column table, the column is named VulnerabilityReferenceId, something like this:
VulnerabilityReferenceId
167554
167555
167556
167557
167558
167559
167560
167561
So I want create a foreach that access to these row and put the value into a variable
I have done:
foreach (DataRow row in _dt.Rows)
{
Debug.WriteLine("VulnerabilityReferenceId: " );
}
But what can I do to access to the value of the current row and put it into an int variable?
This could be an approach that read the field and convert it to the required datatype.
It requires the reference to DataSetExtension assembly from NET3.5 where you could start to find the DataRowExtensions class
foreach (DataRow row in _dt.Rows)
{
int id = row.Field<int>("VulnerabilityReferenceId");
.....
}
Note: I assume that the field VulnerabilityReferenceId is of type integer
You can use column name as an indexer to get the value as object
foreach (DataRow row in _dt.Rows)
{
int vulRefId=Convert.ToInt32(row["VulnerabilityReferenceId"]);
Debug.WriteLine("VulnerabilityReferenceId: " +vulRefId );
}
Try the below:
for(int i=0;i<_dt.Rows.Count;i++)
{
Debug.WriteLine("VulnerabilityReferenceId: "+dt.Rows[i][0].ToString());
}
foreach (DataRow row in _dt.Rows)
{
String stringVal = row["VulnerabilityReferenceId"].ToString();
int myId = Convert.ToInt32(stringVal);
}

How to add new rows to DataTable only under specific columns?

I've got a DataTable, dt2, where I'm trying to add new rows (in the else block of the code below). I cannot simply add the rows within the foreach loop (which I tried with the line dt2.Rows.Add(newRow);) because that screws up the loop counter or something and causes the following error: "Collection was modified; enumeration operation might not execute."
So I tried storing the new row values in a List and then adding the List to the table outside of the loop. This works in the sense that it compiles and it does add something; unfortunately it doesn't take the correct values or column locations but instead displays this crap: System.Collections.Generic.List`1[System.Object]
Also, the information should be displayed in the 3rd, 4th, and 5th index columns under Target_Folder, Target_File, and Target_Checksum, not under Baseline_Folder.
How do I store and display the correct values under the correct columns?
foreach (DataRow drow in dt2.Rows)
{
if (drow["BASELINE_FILE"].ToString() == filename)
{
// do stuff
}
else
{
newRow = dt2.NewRow(); // newRow is a DataRow I declared up above
newRow[3] = directory;
newRow[4] = filename;
newRow[5] = checksumList[j];
newRow[6] = "Missing";
//dt2.Rows.Add(newRow);
// can't add here because that increases the number of rows and screws up the foreach loop
// therefore need to find way to store these values and add outside of loop
newFiles.Add(newRow); // newFiles is a List
}
}
dt2.Rows.Add(newFiles); // this doesn't work properly, doesn't take correct values
I think this is what you really want to do :
DataRow[] drx = dt2.Select(string.Format("BASELINE_FILE = '{0}'" , filename));
if (drx.Length == 1)
{
// do stuff with drx[0]
}
else
{
newRow = dt2.NewRow(); // newRow is a DataRow I declared up above
newRow[3] = directory;
newRow[4] = filename;
newRow[5] = checksumList[j];
newRow[6] = "Missing";
dt2.Rows.Add(newRow);
}
This way you don't need to loop through the rows.
If you're looking to go through each row in the existing grid, this should do it for you. This way currentRows isn't being modified while loop is running as it will be a shallow copy of that list.
var currentRows = from row in dataTable.Rows select row;
foreach (var row in currentRows)
{
if(doStuffCondition){ doStuff();}
else{
DataRow newRow = dataTable.NewRow();
newRow[1] = newValue; //repeat until values are loaded
employeesDataTable.Rows.Add(newRow);
}
}
This is off the top of my head, but something along these lines should work:
DataRow dr = dt2.NewRow();
foreach (ListItem item in newFiles.Items)
{
dr[3] = item[3].ToString();
dr[4] = item[4].ToString();
etc.
}
If you need more guidance, let me know and I'll look harder at it.

DataTable C# Empty column type

I am trying build a DataTable one row at a time using the following code.
foreach (var e in Project.ProjectElements[hi.FakeName].Root.Elements()) {
index = 0;
object[] obj=new object[count];
foreach (var holdingColumn in names) {
string d = e.Attribute(holdingColumn.Key).Value;
obj[index++] = d;
}
dt.Rows.Add(obj);
}
The problem is the DataTable has types tied to the columns. Sometimes im passing null (or an empty string) in that object index and it is telling me that it cant be converted properly to a DateTime (in this case). My question is what should I default this value to, or is there some way to have the DataTable ignore empty values.
Set the AllowDBNull property of the DataColumn to true, then write
if (String.IsNullOrEmpty(d))
obj[index++] = DBNull.Value;
else
obj[index++] = d;

Categories