Adding Array to Existing DataTable - c#

I have a DataTable, dtHOURS, that consists of two columns of data passed from an SQL database and I am trying to include a third column that consists of calculated values within the array, hours. I've looked at many similar asked questions, but none of the solutions seem to work in my case. I've confirmed that the correct values are being stored in the array, but I can't seem to populate those values within column "Total Hours". All the row data comes out blank for this column.
Any help would be appreciated.
Thank you in advance.
//Create new column and row for the "Total Hours" in data table
DataColumn TotalHoursCol;
DataRow TotalHoursRow;
// Create new DataColumn, set DataType,
// ColumnName and add to DataTable.
TotalHoursCol = new DataColumn();
TotalHoursCol.DataType = System.Type.GetType("System.Double");
TotalHoursCol.ColumnName = "Total Hours";
// Add the Column to the Table.
dtHOURS.Columns.Add(TotalHoursCol);
//This loop calculates the total hours for all jobs and adds them to the data table
for (int i = 1; i < numberOfRecordsHours; i++)
{
//Console.WriteLine(dtHOURS.Rows[i]["ID"]);
//Console.WriteLine(dtHOURS.Rows[i]["ACT_RUN_HRS"]);
if ((Convert.ToString(dtHOURS.Rows[i]["ID"])) == (Convert.ToString(dtHOURS.Rows[i-1]["ID"])))
{
hours[i] = (Convert.ToDouble(dtHOURS.Rows[i]["ACT_RUN_HRS"])) + (hours[i-1]);
//Console.WriteLine(hours[i]);
}
else
{
hours[i] = 0;
//Console.WriteLine("NEW JOB");
}
TotalHoursRow = dtHOURS.NewRow();
TotalHoursRow["Total Hours"] = hours[i];
dtHOURS.Rows.Add(TotalHoursRow);
//Console.WriteLine(dtHOURS.Rows[i]["Total Hours"]);
}

If I am understanding the problem correctly, it looks like you are adding a new row instead of assigning to your new column.
Instead of
TotalHoursRow = dtHOURS.NewRow();
TotalHoursRow["Total Hours"] = hours[i];
dtHOURS.Rows.Add(TotalHoursRow);
Just put
dtHOURS.Rows[i]["Total Hours"] = hours[i];

Related

Adding datatype to table columns with ClosedXML

I'm using ClosedXML to create an xlsx-file with some data. In the Excel-sheet I have a table with data. In the columns of the table (not the column of the sheet) I want to specify datatypes.
/* This datatable is created and populated somewhere else in my program*/
Datatable dt = new Datatable();
ws.Cell(t.Position.Row, t.Position.Column).InsertTable(dt);
IXLTables allTables = ws.Tables;
var table = allTables.ElementAt(i);
int j = 1;
/* The options object hold the excel datatypes for each column*/
foreach (var c in option.Tables.ElementAt(i).Columns)
{
table.Column(j).DataType = c.Type;
j++;
}
i++;
The datatype is found and added in the foreach-loop from an options object, how this works in my program is probably not important.
The problem is that when I add a datatype to a column in the table it includes the header of the table. Since the header is "Text" and the value I might specified is Number I get an error. Anyone got an idea how to make it ignore the headerline of the table and simply add datatype to the columns below?
Thanks in advance.
Since setting the data type can work on a per column basis in Excel it's not unreasonable to expect the same from ClosedXml. As you've found it doesn't work like that however. The way I do it is to define a range that selects the whole column except the header. I've not worked with tables the way you are but the following snippet should give you a direction.
IXLWorksheet sheet = wb.Worksheets.Add("Sheet1");
sheet.Cell(1, 1).InsertTable(dt);
foreach (var column in sheet.ColumnsUsed())
{
string columnLetter = column.ColumnLetter();
string rng = $"${columnLetter}2:columnLetter}sheet.RangeUsed().RowCount()}";
sheet.Range(rng).DataType = some data type;
}

Update :Result is not transfered to the orginal dataset. Sorting Rows in Dataset using C#

Update: even though I have got the required result but when the the second function access the data table the value is still the same
It a sequential program with two functions in different classes. First sort and second replace function. So it should sort the value and other function should be able to retrieve the sorted table but when it retrieve the datatable it gives the unsorted table.
I have used acceptchanges() but it also give the same result.
The program is trying to sort the table according to the required field and the result is stored in Sorted table variable. I am trying to copy this to the original i-e sourceTables but it is not working and is adding another row instead of updating [As shown in below dig]. I have tried to copy whole table but it does not work and by adding rows it is not giving the required result. I have used different methods but I am not getting the required result.
List<DataTable> sourceTables = context.GetDataByTable(sourceTable.StringValue);
List<DataTable> targetTables = context.GetDataByTable(targetTable.StringValue, sourceTables.Count);
string orderDesc= orderField.StringValue + " DESC";
for (int i = 0; i < sourceTables.Count; i++)
{
DataView dv = sourceTables[i].DefaultView;
if (orderDirection.StringValue == OrderDirectionAsc)
{
// for Sorting in Ascending Order
dv.Sort = orderField.StringValue;
}
else
{
// for Sorting in Descending Order
dv.Sort = orderDesc;
}
DataTable sortedTable = dv.ToTable();
DataTable dttableNew = sortedTable.Clone();
//sourceTables[i] = sortedTable.Copy();
//targetTables[i] = dv.ToTable();
//targetTables[i] = sortedTable.Copy();
// foreach (DataRow dr in sortedTable.Rows)
//// targetTables[i].Rows.Add(dr.ItemArray);
//}
for (int j = 0; j < sourceTables[i].Rows.Count; j++)
{
if (sourceTable.GetValue().ToString() == targetTable.GetValue().ToString())
{
foreach (DataRow dr in sortedTable.Rows)
{
targetTables[i].Rows.Add(dr.ItemArray);
}
else
{
foreach (DataRow dr in sortedTable.Rows)
{
targetTables[i].Rows.Add(dr.ItemArray);
}
// targetTables[i] = sortedTable.Copy(); does not work
//foreach (DataRow drtableOld in sortedTable.Rows)
//{
// targetTables[i].ImportRow(drtableOld);
//}
Instead of replacing the first values it is adding more rows
any help would be appreciated
If any one have problem with duplicate data or the changes are only local and is not effecting the original data table. Remember to always use .ImportRow(dr) function to add rows to the table and if you use Tables[i].Rows.Add(dr.ItemArray); the changes will affect only the local table and not the original one. Use .clear to remove the old rows from the orginal table. The action done directly on the original function will only effect the rows. If it is done on the clone copy changes will nor affect the original table.
Here is the complete code
DataTable sortTable = dv.ToTable();
if (sTable.GetValue().ToString() == tTable.GetValue().ToString())
{
sTables[i].Clear();
foreach (DataRow dr in sortTable.Rows)
{
sTables[i].ImportRow(dr);
}
sTables[i].AcceptChanges();
}

Show Total of column values in dataGridView

I am a newbie in C# so I don't know if I will address my problem correctly so please bear with me.
I have a dataGridView named dgvShowAllData which has a data source coming from my sqlServer. there are a column named Price.
I want to add a new row at the end of the rows in my dataGridView to show the total of the Price column values.
I've tried multiple solutions and got several errors.
I have found a solution that the sum will execute from the sqlServer.
like below,
Select Sum(Price) from tblProduct
but I got stuck there too. I don't exactly know how to execute two data source in a dataGridview.
Please show me a better way so than I can get the total at the very end of my dataGridView.
use a data table as a data source for your DataGridView. Then add a data row to your data table, Data Table has a compute function.
An example of how I would work this around;
DataTable dt;
dt = yourDataSource; //add your data source to the Data Table
DataRow dr = dt.NewRow();
dr("Price") = dt.Compute("Sum(Price)", "");
dt.Rows.Add(dr);
dgvShowAllData.DataSource = dt;
In your code, create a custom footer row for your dataGridView and populate total value in element within footer row.
Ngengis' solution worked for my implementation. My app does not know the name, type, or number of columns in advance, so I needed to tweak it a bit. I made use of an extension method (by Dmytrii Nagirniak) to check that a DataColumn.DataType is numeric:
public static bool IsNumeric(this DataColumn col)
{
if (col == null)
return false;
var numericTypes = new[] { typeof(Byte), typeof(Decimal), typeof(Double), typeof(Int16), typeof(Int32), typeof(Int64), typeof(SByte), typeof(Single), typeof(UInt16), typeof(UInt32), typeof(UInt64)};
return numericTypes.Contains(col.DataType);
}
And I used a loop to create the total row. I needed to catch a SyntaxErrorException in case the column name didn't work with the Compute() method (aggregated columns with parenthesis in them fail; using a column alias fixes that problem)
//Total Row
if (MakeTotalRow == true)
{
DataRow dr = dt.NewRow();
for (int j = 0; j < dt.Columns.Count; j++)
{
var colName = dt.Columns[j].ColumnName;
if (dt.Columns[j].IsNumeric()) //ensure column data can be summed
{
try
{
dr[j] = dt.Compute("Sum(" + colName + ")", "");
}
catch (SyntaxErrorException e)
{
//possible syntax error in the column name
}
}
}
dt.Rows.Add(dr);
}
At the first you must use LINQ entityframework and then:
You should test these code it`s will you handle, for example, your field in database named by 'Price', so try :
step by step ,
1.Make A List<> from your Database :
List<Database.tblProduct> Lst=new List<Database.tblProduct>;
So you Could Use Query From C#,
Textblock.text=lst.Where(w=>w.PriceId==1).sum(w=>w.Price).tostring("#,##");
it Could Help you.

making rows distinct and showing all the columns

In my project there are two datatables dtFail and dtFailed (dtFailed has nothing but column names declarations). dtFail has duplicate "EmployeeName" column values. so i took a dataview dvFail and did the process to make them distinct as shown in the below code:
dtFail
I tried the below code:
DataView dvFail = new DataView(dtFail);
dtFail = dvFail.ToTable(true, "EmployeeName"); //showing only one column in dtFail
dtFailed (only one column)
If i do like below
DataView dvFail = new DataView(dtFail);
dtFail = dvFail.ToTable(true, "EmployeeName","EmployeeRole","Status");
dtFailed (showing but with duplicate rows)
Then the datatable dtFailed is storing duplicate "EmployeeName" also.
Please Help
Thanks in Advance.
Try this query-
DataTable distinctTable = originalTable.DefaultView.ToTable( /*distinct*/ true);
For more info hit below link-
https://social.msdn.microsoft.com/Forums/en-US/ed9c6a6a-a93e-4bf5-a892-d8471b84aa3b/distinct-in-datatable-or-dataview?forum=adodotnetdataset
I hope this would have helped you.
SOLUTION 1:
Based on the question my understanding is, we need to consider duplicates based on EmployeeName and we need not worry about other columns. If that is the case below solution works better.
foreach(DataRow r in dtFail.AsEnumerable())
{
if (!dt1.AsEnumerable().Any(r1 => r1["EmployeeName"] == r["EmployeeName"]))
{
// if you don't want to copy entire row create new DataRow
// with required fields and add that row.
dt1.Rows.Add(r.ItemArray);
}
}
if you want you can put dt1 back to dtFail.
SOLUTION 2:
If we need to consider distinct rows I prefer below solution.
var temp = dtFail.AsEnumerable().Distinct();
dtFail = temp.CopyToDataTable();
I'm not sure it will be helpful or not. As far as I get from your question that you want EmployeeName to be distinct irrelevant to other columns. But if you do ToTable and turn on the distinct flag it will give all the distinct rows, doesn't matter how many columns are involved there. So if you mention only EmployeeName it will obviously give you distinct EmployeeNames, not all the columns associated with it.
So, thats what I did, initially select only the distinct EmployeeName columns and put it into a temp DataTable dtt.
DataTable dtt = dvFail.DefaultView.ToTable(true, "EmployeeName");
Secondly I've created another temp DataTable where we put the segregated rows from the main DataTable dtFail and set the column names manually.
DataTable TempDataTable = new DataTable();
DataTable dtFailed = new DataTable();
Prepare the columns in the dtFailed DataTable.
if (dtFailed.Columns.Count == 0)
{
dtFailed.Columns.Add("EmployeeName");
dtFailed.Columns.Add("EmployeeRole");
dtFailed.Columns.Add("Status");
dtFailed.Columns.Add("Date");
}
Loop through the distinct EmployeeName dtt DataTable and match the EmployeeName and keep that selected first row in the TempDataTable. Finally all rows transferred into the dtFailed.
for (int j = 0; j < dtt.Rows.Count; j++)
{
string EmployeeName = dtt.Rows[j]["EmployeeName"].ToString();
TempDataTable = dvFail.Select("EmployeeName = " + EmployeeName).CopyToDataTable();
dtFailed.Rows.Add(TempDataTable.Rows[0].ItemArray);
}

How can i add the row dynamically at an exact postion in a dataset

I write a code to add dynamical column and row to a data set but the field is added some where in my data-set so can any one tell how can I resolve this
My code
for (int i = 0; i < AchDB.Amount1.Count; i++)
{
DataColumn dc = new DataColumn("Amount1");
local_ds.Tables[0].Columns.Add(dc);
local_ds.Tables[0].Rows.Add(AchDB.Amount1[i]);
}
I need as per in the image shown
Maybe you can use this:
DataColumn dc = new DataColumn("Amount1");
local_ds.Tables[0].Columns.Add(dc);
for (int i = 0; i < AchDB.Amount1.Count; i++)
{
local_ds.Tables[0].Rows[i]["Amount1"] = AchDB.Amount1[i];
}
I did put the code for adding a new column outside the loop. I think adding the column once will be applicable for all rows.
You can use the "InsertAt" method of DataTable for inserting the row at specific position. For the columns there is no direct way of adding a column at a specific position. When you add a column to a datatable - it always gets added at the last.
dt.Rows.InsertAt(newRowObject,pos);

Categories

Resources