DataColumn Name from DataRow (not DataTable) - c#

I need to iterate the columnname and column datatype from a specific row. All of the examples I have seen have iterated an entire datatable. I want to pass a single row to a function to do a bunch of conditional processing. I want to separate the conditional processing for ease of readability.
This is what I have:
private void doMore(DataRow dr)
{
foreach (DataColumn c in dr.ItemArray) //loop through the columns.
{
MessageBox.Show(c.ColumnName.ToString());
}
}
The error returned is
System.InvalidCastException: Unable to cast object of type 'System.String' to type 'System.Data.DataColumn'.
How would I get the column name from the row or do I have no choice and must pass the entire datatable to the function?

You would still need to go through the DataTable class. But you can do so using your DataRow instance by using the Table property.
foreach (DataColumn c in dr.Table.Columns) //loop through the columns.
{
MessageBox.Show(c.ColumnName);
}

You can make it easier in your code (if you're doing this a lot anyway) by using an extension on the DataRow object, like:
static class Extensions
{
public static string GetColumn(this DataRow Row, int Ordinal)
{
return Row.Table.Columns[Ordinal].ColumnName;
}
}
Then call it using:
string MyColumnName = MyRow.GetColumn(5);

You need something like this:
foreach(DataColumn c in dr.Table.Columns)
{
MessageBox.Show(c.ColumnName);
}

use DataTable object instead:
private void doMore(DataTable dt)
{
foreach(DataColumn dc in dt.Columns)
{
MessageBox.Show(dc.ColumnName);
}
}

Related

DataTable Extension methods C#

I have a method to perform operation in Datatable.
public DataTable SetColumnsOrder(DataTable table, String[] columnNames)
{
int columnIndex = 0;
foreach (var columnName in columnNames)
{
if (table.Columns.Contains(columnName))
{
table.Columns[columnName].SetOrdinal(columnIndex);
columnIndex++;
}
} return table;
}
To access this method I need to do like this
dt = SetColumnsOrder(dt,colNames);
Instead of doing like this, how to create a function to call it like below in c#
dt.SetColumnOrder(colNames);
where the function should take dt as input to perform operations and store back in same dt.
You would need to use an extension method like so:
public static class DataTableExtensions
{
public static DataTable SetColumnsOrder(this DataTable table, string[] columnNames)
{
int columnIndex = 0;
foreach (var columnName in columnNames)
{
if (table.Columns.Contains(columnName))
{
table.Columns[columnName].SetOrdinal(columnIndex);
columnIndex++;
}
}
return table;
}
}
Usage would be:
dt.SetColumnsOrder(columnNames);
And since you're modifying the DataTable, which is a reference type. You can use void as the return type and just access the sorted dt variable
First of all, you don't need to return the same DataTable that you pass in. You could change your method signature to:
public void SetColumnsOrder(DataTable table, String[] columnNames)
and remove the return, and it would still work the same (obviously you'd call it like SetColumnsOrder(dt,colNames); instead of dt = SetColumnsOrder(dt,colNames);. And you should do that, because it's less confusing design.
Then, in order to call it as an extension method, just change the signature again, to:
public static void SetColumnsOrder(this DataTable table, String[] columnNames)
And now you can use it like dt.SetColumnOrder(colNames);.
Change your signature from
public DataTable SetColumnsOrder(DataTable table, String[] columnNames)
to
public static DataTable SetColumnsOrder(this DataTable table, String[] columnNames)

The given DataRow is not in the current DataRowCollection when tried move item from DataGridView to another

I have two DataGridView like this:
Button selected will move DataRow of DataGridView to another DataGridView.
My code like this:
public static DataRow[] GetSelectedDataRows(DataGridView grid)
{
DataRow[] dRows = new DataRow[grid.SelectedRows.Count];
for (int i = 0; i < grid.SelectedRows.Count; i++)
dRows[i] = ((DataRowView)grid.SelectedRows[i].DataBoundItem).Row;
return dRows;
}
public void MoveRows(DataTable src, DataTable dest, DataRow[] rows)
{
foreach (DataRow row in rows)
{
// add to dest
dest.Rows.Add(row.ItemArray);
// remove from src
src.Rows.Remove(row);
}
}
I use it in Event btnMoveToRight_Click().
MoveRows(dtUser, dtUserStop, GetSelectedDataRows(dgvUser));
It throws exception error like:
The given DataRow is not in the current DataRowCollection
at line:
src.Rows.Remove(row);
You can't change the Table field of a DataRow.
So you need to create a new row and also copy the data separately, maybe like this:
public void MoveRows(DataTable src, DataTable dest, DataRow[] rows)
{
foreach (DataRow row in rows)
{
// create empty row
DataRow newrow = dest.NewRow();
// copy data
newrow.ItemArray = row.ItemArray;
// add to dest
dest.Rows.Add(newrow); // (*)
// remove from src NOTE: This may or may not throw an RowNotInTableException
// to avoid it you can skip the Remove and use the loop below instead..
src.Rows.Remove(row);
}
// alternative way of removing the rows..
//foreach (DataGridViewRow item in this.dgvUser.SelectedRows)
//{
// dgvUser.Rows.RemoveAt(item.Index);
//}
}
(*) An even shorter way to clone a DataRow is using this overload of the Add method:
dest.Rows.Add(row.ItemArray);
No need for the newrow now. Note that you may want to copy the RowState from the old to the new row!? See here and here for examples of changing the RowState
If you find you need to remove the DataRows via removing the DataGridViewRows you should add the DGV to the parameters of the MoveRows function to avoid an unecessary dependence..!
Of course this assumes that the DataTables have the same structure, maybe because one is a (structural) clone of the other:
dest = src.Clone();
DataRow has a DataTable property on it (DataRow.Table).
This leads me to think that adding the row to a new table breaks the association with the old DataTable, so you don't need to call src.Rows.Remove(row).

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 Avoid Explicit Casting using Generics

I have a routine which converts all the data in a DataGridView to a corresponding DataTable. I want to extend this method to incorporate the ability to convert just the selected range of the DataGridView. I can clearly do this using basic logic if (bIsSelection) /*Do stuff*/ else /*Do other stuff*/ but I would like to use generics here. The problem is that the full DataGridView range is a DataGridViewColumnCollection and the selected range will be a DataGridViewSelectedColumnCollection and C# does not seem to like any conversion between the two, or allow implicit typing in the case of generics.
The first part of my code was
public static DataTable BuildDataSetFromDgv(DataGridView _dataGridView,
string strTabName)
{
DataTable dt = new DataTable();
dt.TableName = strTabName;
foreach (DataGridViewColumn col in _dataGridView.Columns)
dt.Columns.Add(col.DataPropertyName, col.ValueType);
and I have attempted
public static DataTable BuildDataSetFromDgv<T>(DataGridView _dataGridView,
string strTabName, ICollection<T> _columnColl, ICollection<T> _rowColl)
{
DataTable dt = new DataTable();
dt.TableName = strTabName;
//foreach (DataGridViewColumn col in _dataGridView.Columns)
foreach (DataGridViewColumn col in _columnColl)
dt.Columns.Add(col.DataPropertyName, col.ValueType);
which does not work due to the implicit conversion, and changing _columnColl to _columnColl as DataGridView[Selected]ColumnCollection defeats the objective.
How do I make this work with generics in this case?
Thanks for your time.
I am not sure why you need a generic one - both are collection of DataGridViewColumn. For example, why below shouldn't work for you
public static DataTable BuildDataSetFromDgv(DataGridView _dataGridView,
string strTabName, IEnumerable columns)
{
DataTable dt = new DataTable();
dt.TableName = strTabName;
var dvgColumns = columns.Cast<DataGridViewColumn>();
foreach (var col in dvgColumns)
dt.Columns.Add(col.DataPropertyName, col.ValueType);

Categories