I am using TemplateEngine.Docx, Template engine for generating Word docx
I am trying to MAP DataTable Result to Word Document Table, Below Code snippet is doing this by hard coding
var valuesToFill = new Content(
// Add table.
new TableContent("Team Members Table")
.AddRow(
new FieldContent("Name", "Eric"),
new FieldContent("Role", "Program Manager"))
.AddRow(
new FieldContent("Name", "Bob"),
new FieldContent("Role", "Developer")),
// Add field inside table that not to propagate.
new FieldContent("Count", "2")
);
I have Tried below code but I am not able to figure it out,
DataTable dt = new DataTable();
dt.Clear();
dt.Columns.Add("SOE_DT");
dt.Columns.Add("SOE_TM");
dt.Columns.Add("SOE_EV");
dt.Rows.Add(new object[] { "19/07/2017", "16:00", "This is First Event" });
dt.Rows.Add(new object[] { "19/07/2017", "16:30", "This is Second Event" });
dt.Rows.Add(new object[] { "19/07/2017", "17:00", "This is Third Event" });
dt.Rows.Add(new object[] { "19/07/2017", "18:00", "This is Fourth Event" });
TableContent tblSEQOfEvents = new TableContent("SEQOfEvents");
foreach (DataRow dtRow in dt.Rows)
{
//I Need to Add here tblSEQOfEvents.AddRow
foreach (DataColumn dc in dt.Columns)
{
tblSEQOfEvents.AddRow(
new FieldContent(dc.ColumnName, dtRow[dc].ToString()
));
}
}
The Result is showing in Image. I know that because of for each column loop it loops 12 times instead of 4 times I just show the snipped if some one help me to correct it.
Thanks
UPDATE 1
by This Stackoverflow Q/A I am able to get it done by following code, is it right way or it can me improve ?
foreach (DataRow dtRow in dt.Rows)
{
string SOE_DT = dtRow["SOE_DT"].ToString();
string SOE_TM = dtRow["SOE_TM"].ToString();
string SOE_EV = dtRow["SOE_EV"].ToString();
tblSEQOfEvents.AddRow(
new FieldContent("SOE_DT", SOE_DT),
new FieldContent("SOE_TM", SOE_TM),
new FieldContent("SOE_EV", SOE_EV)
);
}
TableContent.AddRow accepts IContentItem[]..
may be something like this..
foreach (DataRow dtRow in dt.Rows)
{
//I Need to Add here tblSEQOfEvents.AddRow
List<IContentItem> items = new List<IContentItem>();
foreach (DataColumn dc in dt.Columns)
{
items.Add(new FieldContent(dc.ColumnName, dtRow[dc].ToString()));
}
tblSEQOfEvents.AddRow(items.ToArray());
}
Related
I'm new to C#. I know that datatable is very efficient for reading an entire SQL table and outputting data to griddataview. However I need to do some parsing before storing the data in my griddataview. I was thinking reading the table row by row and grouping the data when applicable. Would a datatable or a list be more applicable in my case?
ORIGINAL TABLE PARSED TABLE I need to pass to datagridview
Name Workdate Name M T W TH F SAT SUN
Nicole WED Nicole Y Y Y
Nicole THR Jason Y
Nicole MON
Jason Tue
Try following :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Dictionary<string, string> dict = new Dictionary<string, string>() {
{"MON", "M"},{"TUE", "T"},{"WED", "W"},{"THR", "TH"},{"FRI", "F"},{"SAT", "SAT"},{"SUN", "SUN"}};
DataTable dt = new DataTable();
dt.Columns.Add("Name", typeof(string));
dt.Columns.Add("Workdate", typeof(string));
dt.Rows.Add(new object[] { "Nicole", "WED" });
dt.Rows.Add(new object[] { "Nicole", "THR" });
dt.Rows.Add(new object[] { "Nicole", "MON" });
dt.Rows.Add(new object[] { "Jason", "TUE" });
DataTable pivot = new DataTable();
pivot.Columns.Add("Name",typeof(string));
DataColumn[] columns = dict.Select(x => new DataColumn(x.Value, typeof(string))).ToArray();
pivot.Columns.AddRange(columns);
var people = dt.AsEnumerable().GroupBy(x => x.Field<string>("Name")).ToArray();
foreach (var person in people)
{
DataRow pivotRow = pivot.Rows.Add();
pivotRow["Name"] = person.Key;
foreach (DataRow row in person)
{
string day = row.Field<string>("Workdate");
pivotRow[dict[day]] = "Y";
}
}
}
}
}
I have four tables (employees, allowances,deductions and Ajenda these are main tables , when i save employees financial details i save them in a different tables as image .
I want to display the employees detail and financial details in a horizontally way .
I'm using C# and SQLServer 2012 .
first table contains employees main details , second contain employees id with there allowances and other tables .
My tables
Here is my code before somebody closes it again. I decided not to use group since there would be a lot of left outer joins which would complicate solution. Decided just to create a table and then add the data directly to the results table.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
DataTable employees = new DataTable();
employees.Columns.Add("empID", typeof(int));
employees.Columns.Add("emp_name", typeof(string));
employees.Columns.Add("emp_tele", typeof(string));
employees.Rows.Add(new object[] { 1, "David", "025896325" });
employees.Rows.Add(new object[] { 2, "John", "856985658" });
employees.Rows.Add(new object[] { 3, "Micheal", "654687887" });
DataTable allowances = new DataTable();
allowances.Columns.Add("empID", typeof(int));
allowances.Columns.Add("allow_name", typeof(string));
allowances.Columns.Add("allow_Amount", typeof(int));
allowances.Rows.Add(new object[] { 1, "allow1", 100 });
allowances.Rows.Add(new object[] { 1, "allow2", 200 });
allowances.Rows.Add(new object[] { 1, "allow3", 300 });
allowances.Rows.Add(new object[] { 2, "allow1", 100 });
allowances.Rows.Add(new object[] { 2, "allow2", 200 });
DataTable deductions = new DataTable();
deductions.Columns.Add("empID", typeof(int));
deductions.Columns.Add("Dedu_name", typeof(string));
deductions.Columns.Add("Dedu_Amount", typeof(int));
deductions.Rows.Add(new object[] { 1, "ded1", 10 });
deductions.Rows.Add(new object[] { 1, "ded2", 5 });
deductions.Rows.Add(new object[] { 2, "ded1", 10 });
DataTable ajenda = new DataTable();
ajenda.Columns.Add("empID", typeof(int));
ajenda.Columns.Add("ajenda_name", typeof(string));
ajenda.Columns.Add("ajenda_Amount", typeof(int));
ajenda.Rows.Add(new object[] { 1, "aj1", 200 });
ajenda.Rows.Add(new object[] { 1, "aj1", 200 });
ajenda.Rows.Add(new object[] { 1, "aj2", 300 });
DataTable results = employees.Clone();
string[] allow_names = allowances.AsEnumerable().Select(x => x.Field<string>("allow_name")).Distinct().OrderBy(x => x).ToArray();
foreach (string name in allow_names)
{
results.Columns.Add(name, typeof(string));
}
string[] dedu_names = deductions.AsEnumerable().Select(x => x.Field<string>("Dedu_name")).Distinct().OrderBy(x => x).ToArray();
foreach (string name in dedu_names)
{
results.Columns.Add(name, typeof(string));
}
string[] ajenda_names = ajenda.AsEnumerable().Select(x => x.Field<string>("ajenda_name")).Distinct().OrderBy(x => x).ToArray();
foreach (string name in ajenda_names)
{
results.Columns.Add(name, typeof(string));
}
//add employees to result table
foreach(DataRow row in employees.AsEnumerable())
{
results.Rows.Add(row.ItemArray);
}
var groupAllownaces = allowances.AsEnumerable().GroupBy(x => x.Field<int>("empID"));
foreach (var group in groupAllownaces)
{
DataRow employeeRow = results.AsEnumerable().Where(x => x.Field<int>("empID") == group.Key).First();
foreach (DataRow row in group)
{
employeeRow[row.Field<string>("allow_name")] = row.Field<int>("allow_Amount");
}
}
var groupDeductions = deductions.AsEnumerable().GroupBy(x => x.Field<int>("empID"));
foreach (var group in groupDeductions)
{
DataRow employeeRow = results.AsEnumerable().Where(x => x.Field<int>("empID") == group.Key).First();
foreach (DataRow row in group)
{
employeeRow[row.Field<string>("Dedu_name")] = row.Field<int>("Dedu_Amount");
}
}
var groupAjenda = ajenda.AsEnumerable().GroupBy(x => x.Field<int>("empID"));
foreach (var group in groupAjenda)
{
DataRow employeeRow = results.AsEnumerable().Where(x => x.Field<int>("empID") == group.Key).First();
foreach (DataRow row in group)
{
employeeRow[row.Field<string>("ajenda_name")] = row.Field<int>("ajenda_Amount");
}
}
}
}
}
I have a string like this:
"Product,Price,Condition
Cd,13,New
Book,9,Used
"
Which is being passed like this:
"Product,Price,Condition\r\Cd,13,New\r\nBook,9,Used"
How could I convert it to DataTable?
Trying to do it with this helper function:
DataTable dataTable = new DataTable();
bool columnsAdded = false;
foreach (string row in data.Split(new string[] { "\r\n" }, StringSplitOptions.None))
{
DataRow dataRow = dataTable.NewRow();
foreach (string cell in row.Split(','))
{
string[] keyValue = cell.Split('~');
if (!columnsAdded)
{
DataColumn dataColumn = new DataColumn(keyValue[0]);
dataTable.Columns.Add(dataColumn);
}
dataRow[keyValue[0]] = keyValue[1];
}
columnsAdded = true;
dataTable.Rows.Add(dataRow);
}
return dataTable;
However I don't get that "connecting cells with appropriate columns" part - my cells don't have ~ in string[] keyValue = cell.Split('~'); and I obviously get an IndexOutOfRange at DataColumn dataColumn = new DataColumn(keyValue[0]);
Based on your implementation, I have written the code for you, I have not tested it. But you can use the concept.
DataRow dataRow = dataTable.NewRow();
int i = 0;
foreach (string cell in row.Split(','))
{
if (!columnsAdded)
{
DataColumn dataColumn = new DataColumn(cell);
dataTable.Columns.Add(dataColumn);
}
else
{
dataRow[i] = cell;
}
i++;
}
if(columnsAdded)
{
dataTable.Rows.Add(dataRow);
}
columnsAdded = true;
You can do that simply with Linq (and actually there is LinqToCSV on Nuget, maybe you would prefer that):
void Main()
{
string data = #"Product,Price,Condition
Cd,13,New
Book,9,Used
";
var table = ToTable(data);
Form f = new Form();
var dgv = new DataGridView { Dock = DockStyle.Fill, DataSource = table };
f.Controls.Add(dgv);
f.Show();
}
private DataTable ToTable(string CSV)
{
DataTable dataTable = new DataTable();
var lines = CSV.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
foreach (var colname in lines[0].Split(','))
{
dataTable.Columns.Add(new DataColumn(colname));
}
foreach (var row in lines.Where((r, i) => i > 0))
{
dataTable.Rows.Add(row.Split(','));
}
return dataTable;
}
You can split given string into flattened string array in one call. Then you can iterate through the array and populate list of objects.
That part is optional, since you can immediately populate DataTable but I think it's way easier (more maintainable) to work with strongly-typed objects when dealing with DataTable.
string input = "Product,Price,Condition\r\nCd,13,New\r\nBook,9,Used";
string[] deconstructedInput = input.Split(new string[] { "\r\n", "," }, StringSplitOptions.None);
List<Product> products = new List<Product>();
for (int i = 3; i < deconstructedInput.Length; i += 3)
{
products.Add(new Product
{
Name = deconstructedInput[i],
Price = Decimal.Parse(deconstructedInput[i + 1]),
Condition = deconstructedInput[i + 2]
});
}
public class Product
{
public string Name { get; set; }
public decimal Price { get; set; }
public string Condition { get; set; }
}
So, products collection holds 2 objects which you can easily iterate over and populate your DataTable.
Note: This requires further checks to avoid possible runtime exceptions, also it is not dynamic. That means, if you have differently structured input it won't work.
DataTable dataTable = new DataTable();
dataTable.Columns.Add(new DataColumn(nameof(Product.Name)));
dataTable.Columns.Add(new DataColumn(nameof(Product.Price)));
dataTable.Columns.Add(new DataColumn(nameof(Product.Condition)));
foreach (var product in products)
{
var row = dataTable.NewRow();
row[nameof(Product.Name)] = product.Name;
row[nameof(Product.Price)] = product.Price;
row[nameof(Product.Condition)] = product.Condition;
dataTable.Rows.Add(row);
}
I am adding rows dynamically, as well as columns, into a datatable. The rows add as far as I can see, but as soon as I run the code nothing appears. It's like it's refreshing the table once the foreach loop finishes? Rookie question. Sorry.
summaryTable.Columns.Add("StationName", typeof(string));
summaryTable.Columns.Add("DepartmentCode", typeof(string));
var row = summaryTable.NewRow();
foreach (var item in issuesByClass)
{
row.SetField("StationName", item.StationName);
row.SetField("DepartmentCode", item.DepartmentCode);
foreach (var itemClass in item.Lookup)
{
if (!itemClassLookup.ContainsKey(itemClass.Key)) continue;
var itemClassValue = itemClassLookup[itemClass.Key];
// Ensure column hasn't been added before
if (!summaryTable.Columns.Contains(itemClassValue))
{
summaryTable.Columns.Add(itemClassValue, typeof(decimal));
}
row.SetField(itemClassValue, itemClass.Sum());
}
if (!summaryTable.Columns.Contains("GrandTotal"))
{
summaryTable.Columns.Add("GrandTotal", typeof(decimal));
}
row.SetField("GrandTotal", item.GrandTotal);
}
return summaryTable;
Small windows form app example:
public Form1()
{
this.InitializeComponent();
this.Test();
}
public void Test()
{
var dt = new DataTable();
var subs = new[] { "Sub 1", "Sub 2", "Sub 3" };
var row = dt.NewRow();
foreach (var sub in subs)
{
if (!dt.Columns.Contains("Subs"))
{
dt.Columns.Add("Subs");
}
row.SetField("Subs", sub);
}
dt.Columns.Add("Test");
row.SetField("Test", 1M);
this.dataGridView1.DataSource = dt;
}
NewRow() doesn't add the row. You need to do that manually at the bottom of the loop via .Rows.Add(row). You should also probably create the NewRow() per iteration.
foreach (var item in issuesByClass)
{
var row = summaryTable.NewRow();
// ...
summaryTable.Rows.Add(row);
}
This code works good it takes and matches all the unit_no and vehiclename together but it only shows the matches i also need the ones that dont match on.
I am loading a datagrid in WPF with SQLserver data and another Datagrid from oracle data.
private void GetSQLOraclelinqData()
{
var TstarData = GetTrackstarTruckData();
var M5Data = GetM5Data();
DataTable ComTable = new DataTable();
foreach (DataColumn OraColumn in M5Data.Columns)
{
ComTable.Columns.Add(OraColumn.ColumnName, OraColumn.DataType);
}
foreach (DataColumn SQLColumn in TstarData.Columns)
{
if (SQLColumn.ColumnName == "VehicleName")
ComTable.Columns.Add(SQLColumn.ColumnName + "2", SQLColumn.DataType);
else
ComTable.Columns.Add(SQLColumn.ColumnName, SQLColumn.DataType);
}
var results = M5Data.AsEnumerable().Join(TstarData.AsEnumerable(),
a => a.Field<String>("Unit_No"),
b => b.Field<String>("VehicleName"),
(a, b) =>
{
DataRow row = ComTable.NewRow();
row.ItemArray = a.ItemArray.Concat(b.ItemArray).ToArray();
ComTable.Rows.Add(row);
return row;
}).ToList();