Updating values in DataTable doesn't work - c#

I have code like this:
DataTable dt = new DataTable();
// (...) getting data, displaying on DataGridView - all works fine
int columns = dt.Columns.Count; // getting column count
foreach (DataRow row in dt.Rows)
{
for (int c = 0; c < columns; c++) // c is column index
{
// all old values are positive for debugging
double oldVal = Convert.ToDouble(row.ItemArray[c]);
// new values should become negative
double newVal = oldVal * -1;
row.ItemArray[c] = newVal; // im trying to update value like this
// THIS SHOWS POSITIVE NUMBERS (NOT UPDATED)
this.Text = row.ItemArray[c].ToString(); // this is simple debug
}
}
This is a little more complicated, i simplified code.
Why my values are not updated?
Added later:
One more important thing. This data comes from database view, not table. Of course I want to change that data in my DataTable object, not in database.

In the end do this
dt.AcceptChanges();
This Commits all the changes made to this table since the last time AcceptChanges() was called.
DataTable dt = new DataTable();
// (...) getting data, displaying on DataGridView - all works fine
int columns = dt.Columns.Count; // getting column count
foreach (DataRow row in dt.Rows)
{
foreach (DataColumn c in dt.Columns)
{
// all old values are positive for debugging
double oldVal = Convert.ToDouble(row[c]);
// new values should become negative
double newVal = oldVal * -1;
row[c] = newVal; // im trying to update value like this
// THIS SHOWS POSITIVE NUMBERS (NOT UPDATED)
this.Text = row[c].ToString(); // this is simple debug
}
}
dt.AcceptChanges();
EDIT (Added explaination):
Changes to ItemArray elements are not tracked, so no changes are reflected in the datatable values
However you can use ItemArray to change all the row at once, like this:
dt.Rows[0].ItemArray = new object[] {"new value"};
In this case the changes are tracked, and are reflected in datatable.

Update your foreach loop as
foreach (DataRow row in dt.Rows)
{
for (int c = 0; c < columns; c++) // c is column index
{
double oldVal = Convert.ToDouble(row[c]);
double newVal = -oldVal;
row[c] = newVal;
this.Text = row[c].ToString();
}
}
or you can use foreachinstead of for loop as:
foreach (DataRow row in dt.Rows)
{
foreach (DataColumn c in dt.Columns)
{
double oldVal = Convert.ToDouble(row[c]);
double newVal = -oldVal;
row[c] = newVal;
this.Text = row[c].ToString();
}
}

Related

ClosedXml Excel Add multiple values to Rows

Trying to add values from an array string[] to a row in Excel.
When I'm trying to use dt.Rows.Add(string[i]) it is added to the Excel sheet. The problem is it is added vertically, which is quite obvious because I'm only adding one item to the row and then insert a new row. My question now is how to add every item from the string[] to one row so that my data is displayed horizontally.
For example string[] values = {"a","b","c","d"};
The output I have at the moment:
a
b
c
d
The output I want:
a b c d (each in a different cell).
A1 = a
B1 = b
...
I've already been able to add columns to the worksheet, I only need my data to be right.
This is my code for now.
//Add columns
dt.Columns.AddRange(columns.Select(c => new DataColumn(c.ToString())).ToArray());
List<string> temp;
string[] values;
for (int i = 0; i < 7; i++)
{
temp = new List<string>();
temp.Add(timeStamps[i].ToString());
foreach (var item in tagCollection)
{
if (timeStamps[i].Date == item.time)
{
temp.Add(item.min);
temp.Add(item.max);
temp.Add(item.avg);
}
}
int index = 0;
values = new string[temp.Count];
foreach (var item in temp)
{
values[index] = item;
dt.Rows.Add(values[index]);
index++;
}
}
//Convert datatable to dataset and add it to the workbook as worksheet
ds.Tables.Add(dt);
workbook.Worksheets.Add(ds);
The solution may go through the following:
string[] cars = { "Volvo", "BMW", "Mazda" };
table.Rows.Add(cars[0].ToString(), cars[1].ToString(), cars[2].ToString());
Output:
Just need to adapt to your own code.
You've to guarantee that your Datasheet has the columns needed to display all data in the same row. If you didn't do that, for sure it will generate a matrix error.
This works for me. I Changed the foreach loop and discoverd that there was a NewRow() method.
int index = 0;
values = new string[temp.Count];
DataRow newRow;
newRow = dt.NewRow();
foreach (var item in temp) {
values[index] = item;
newRow.ItemArray = temp.Cast<object>().ToArray();
index++;
}
dt.Rows.Add(newRow);

Check empty rows in datatable in Visual Studio 2005, no LINQ

I've uploaded data to a datatable from a excel file. Whats the best way to check empty rows in datatable. NB: Need solution for Visual Studio 2005. Cant use linq.
foreach (DataRow row in result.Rows)
{
//check if row is empty
//if not continue processing data
//else remove the row from datatable
}
Currently the solution in my mind is inside foreach loop, put another foreach loop and check each column. If all columns are null, remove the row from datatable.
Is there any other best method. Does the above method takes more time to execute as there is another for each loop. There will be lots of rows in the datatable.
Edited:
I've got one code:
private bool checkIfRowEmpty(DataRow row)
{
var r = (DataRow)row;
int emptyCount = 0;
int itemArrayCount = r.ItemArray.Length;
foreach (var i in r.ItemArray) if (string.IsNullOrWhiteSpace(i.ToString())) emptyCount++;
if (emptyCount == itemArrayCount) return false;
else return true;
}
Is this okay? Or should I use any solution from below? Which one is good?
Here is one approach - to iterate through all rows and all columns
DataTable table = new DataTable();
List<int> rowsToRemove = new List<int>();
for (int i = 0; i < table.Rows.Count; i++)
{
DataRow row = table.Rows[i];
foreach (DataColumn col in row.Table.Columns)
{
bool skip = false;
if (row[col] != null)
{
//this column is not null, so mark skip flag as true
skip = true;
}
if (skip)
//this row should be skipped because it has at least one column that isn't null
break;
else
rowsToRemove.Add(i);
//mark this row's index for deletion
}
}
//loop through list in reverse order and remove rows by their index
for (int i = rowsToRemove.Count; i > 0; i--)
table.Rows.RemoveAt(i);
Best solution I can think of is the following one:
public bool IsRowEmpty(DataRow row)
{
if (row == null)
return true;
foreach(var value in row.ItemArray)
{
if (value != null)
return false;
}
return true;
}
Then from your main code:
foreach (DataRow row in result.Rows)
{
if(!IsRowEmpty(row))
{
// Row is not empty.
}
}
Hello,
You can simply achive this using DataView : like this -
DataView dv = yourTable.DefaultView;
dv.Sort = "column_1,column_2";
DataTable dtNew = dv.ToTable(true, "column_1", "column_2",...,"column_n"); // please mention all columns here
dtNew.Rows.RemoveAt(0);

Add specific rows from dataGridView depending on search value

Following issue:
I have a datatable and a list which contains specific values.
routIds = col1Items.Distinct().ToList();
String searchValue = String.Empty;
int rowIndex = -1;
for (int i = 0; i < routIds.Count; i++)
{
searchValue = routIds[i];
foreach (DataGridViewRow row in form1.dataGridView5.Rows)
{
if (row.Cells[form1.routingIdBox.Text].Value != null) // Need to check for null if new row is exposed
{
if (row.Cells[form1.routingIdBox.Text].Value.ToString().Equals(searchValue))
{
rowIndex = row.Index;
foreach (DataGridViewColumn column in form1.dataGridView5.Columns)
dtRout.Columns.Add(column.Name);
for (int k = 0; k < form1.dataGridView5.Rows.Count; k++)
{
dtRout.Rows.Add();
for (int j = 0; j < form1.dataGridView5.Columns.Count; j++)
{
datTable.Rows[k][j] = form1.dataGridView5.Rows[rowIndex].Cells[j].Value;
}
}
}
}
}
}
I want to search the first column from my datagridview and check if it matches a specific value (from my array - routIds). If yes then I want to add the whole row into a datatable but I don't know how this works exactly. Tried around but I get exceptions (specific row not found).
Assuming you have a DataTable as your underlying DataSource. I would not iterate through the DataGridViewRows.
DataTable dataSource = dataGridView.DataSource as DataTable; // if it is a DataTable. If not, please specify in your question
// let's make a DataTable, which is a copy of your DataSource
DataTable dataTableFoundIds = new DataTable();
foreach (DataColumn column in dataSource.Columns)
dataTableFoundIds.Columns.Add(column.ColumnName, column.DataType);
// iterate through your routeIds
foreach (int id in routeIds)
{
var row = dataSource.AsEnumerable().FirstOrDefault(item => item["col1"].Equals(id)); // take the first row in your DataSource that matches your routeId
if (row != null)
{
dataTableFoundIds.Rows.Add(row.ItemArray); // if we find something, insert the whole row of our source table
}
}
Hope this helps!
UPDATE: if you want to find all occurances:
foreach (int id in routeIds)
{
var rows = dataSource.AsEnumerable().Where(item => item["col1"].Equals(id)); // take all rows in your DataSource that match your routeId
foreach(var row in rows)
{
dataTableFoundIds.Rows.Add(row.ItemArray); // if we find something, insert the whole row of our source table
}
}

datatable get specific column from row

I have the following:
//a datatable with some rows and columns lets say 5x5
var datatable = new DataTable();
var numberofrows = datatable.rows.count;
for (int i = 0; i < numberofrows; i++) {
//for each row, get the 3rd column
var cell = datatable.rows[i].???
}
how do I get the 3rd column for each row?
for 3rd column
var cellValue = datatable.Rows[i][2];
better, if you know the column name,
var cellValue = datatable.Rows[i]["column_name"];
If the table contains 2 columns "Property" and "Value". Contents can be inserted as follows
table.Columns.Add("Property", typeof(string));
table.Columns.Add("Value", typeof(string));
table.Rows.Add("P1", "abc");
table.Rows.Add("P2", "xyz");
To retrive contents of specific column
foreach (DataRow row in table.Rows)
{
if (row["Property"].ToString() == "P1")
{
var value = row["Value"].ToString();
}
}
we can read the particular column values by like this
foreach (DataTable table in ds.Tables)
{
if (table.TableName == "Table1")
{
for (int j = 0; j < table.Rows.Count; j++)
{
int a = Convert.ToInt32( table.Rows[j].ItemArray[3]);
int b = Convert.ToInt32(table.Rows[j].ItemArray[4]);
}
}
}
You can iterate thru the datatable and get every row, which can be thought as an array, so you can pick each element of that particular row using an index (and can also use the name of the column instead of the index, i.e.: row["column3 name"]).
foreach(DataRow row in datatable)
{
Console.WriteLine(row[2]);
}

How to sum columns in a dataTable?

How can I get a sum for all the columns in a datatable? Say I had the following table. How can I calculate the "total" row? It should be easy to add total row to a datatable.
Columns hits uniques sigups, etc...
Rows
1 12 1 23
2 1 0 5
3 6 2 9
total 19 3 37
Update
I ended up with this. It was the only thing I could get to work.
For Each col As DataColumn In TotalsTable.Columns
If col.DataType.Name = "DateTime" Then
count = count + 1
Continue For
End If
Dim colTotal As Double = 0
Dim value As Double
For Each row As DataRow In TotalsTable.Rows
If Double.TryParse(row(col), value) Then
colTotal += Double.Parse(row(col))
End If
Next
totalRow(count) = colTotal
count = count + 1
Next
There is also a way to do this without loops using the DataTable.Compute Method. The following example comes from that page. You can see that the code used is pretty simple.:
private void ComputeBySalesSalesID(DataSet dataSet)
{
// Presumes a DataTable named "Orders" that has a column named "Total."
DataTable table;
table = dataSet.Tables["Orders"];
// Declare an object variable.
object sumObject;
sumObject = table.Compute("Sum(Total)", "EmpID = 5");
}
I must add that if you do not need to filter the results, you can always pass an empty string:
sumObject = table.Compute("Sum(Total)", "")
Try this:
DataTable dt = new DataTable();
int sum = 0;
foreach (DataRow dr in dt.Rows)
{
foreach (DataColumn dc in dt.Columns)
{
sum += (int)dr[dc];
}
}
I doubt that this is what you want but your question is a little bit vague
Dim totalCount As Int32 = DataTable1.Columns.Count * DataTable1.Rows.Count
If all your columns are numeric-columns you might want this:
You could use DataTable.Compute to Sum all values in the column.
Dim totalCount As Double
For Each col As DataColumn In DataTable1.Columns
totalCount += Double.Parse(DataTable1.Compute(String.Format("SUM({0})", col.ColumnName), Nothing).ToString)
Next
After you've edited your question and added more informations, this should work:
Dim totalRow = DataTable1.NewRow
For Each col As DataColumn In DataTable1.Columns
totalRow(col.ColumnName) = Double.Parse(DataTable1.Compute("SUM(" & col.ColumnName & ")", Nothing).ToString)
Next
DataTable1.Rows.Add(totalRow)
You can loop through the DataColumn and DataRow collections in your DataTable:
// Sum rows.
foreach (DataRow row in dt.Rows) {
int rowTotal = 0;
foreach (DataColumn col in row.Table.Columns) {
Console.WriteLine(row[col]);
rowTotal += Int32.Parse(row[col].ToString());
}
Console.WriteLine("row total: {0}", rowTotal);
}
// Sum columns.
foreach (DataColumn col in dt.Columns) {
int colTotal = 0;
foreach (DataRow row in col.Table.Rows) {
Console.WriteLine(row[col]);
colTotal += Int32.Parse(row[col].ToString());
}
Console.WriteLine("column total: {0}", colTotal);
}
Beware: The code above does not do any sort of checking before casting an object to an int.
EDIT: add a DataRow displaying the column sums
Try this to create a new row to display your column sums:
DataRow totalsRow = dt.NewRow();
foreach (DataColumn col in dt.Columns) {
int colTotal = 0;
foreach (DataRow row in col.Table.Rows) {
colTotal += Int32.Parse(row[col].ToString());
}
totalsRow[col.ColumnName] = colTotal;
}
dt.Rows.Add(totalsRow);
This approach is fine if the data type of any of your DataTable's DataRows are non-numeric or if you want to inspect the value of each cell as you sum. Otherwise I believe #Tim's response using DataTable.Compute is a better.
It's a pity to use .NET and not use collections and lambda to save your time and code lines
This is an example of how this works:
Transform yourDataTable to Enumerable, filter it if you want , according a "FILTER_ROWS_FIELD" column, and if you want, group your data by a "A_GROUP_BY_FIELD".
Then get the count, the sum, or whatever you wish.
If you want a count and a sum without grouby don't group the data
var groupedData = from b in yourDataTable.AsEnumerable().Where(r=>r.Field<int>("FILTER_ROWS_FIELD").Equals(9999))
group b by b.Field<string>("A_GROUP_BY_FIELD") into g
select new
{
tag = g.Key,
count = g.Count(),
sum = g.Sum(c => c.Field<double>("rvMoney"))
};
for (int i=0;i<=dtB.Columns.Count-1;i++)
{
array(0, i) = dtB.Compute("SUM([" & dtB.Columns(i).ColumnName & "])", "")
}

Categories