LINQ : Join 3 datatables and add calculated field - c#

I've got three tables of Datatable type:
Table1: Id<Int64>, ParamX<string>;
Table2: Id<Int64>;
Table3: Id<Int64>, ParamA<double>, ParamB<Int16>;
I want to Join them by ID field and create Table4 with calculated field ParamC<double>=ParamA<double>*ParamB<Int16>
The result should be datatable:
Table4: Id<Int64>, ParamX<string>, ParamA<double>, ParamB<Int16>, ParamC<double>
Is it possible to make it in single LINQ query?
madace

You cannot create or fill tables in a LINQ query, a query is not supposed to cause side-effects. You can prepare the data you want to insert into the new table with LINQ:
var query = from r1 in Table1.AsEnumerable()
join r2 in Table2.AsEnumerable()
on r1.Field<long>("ID") equals r2.Field<long>("ID")
join r3 in Table3.AsEnumerable()
on r2.Field<long>("ID") equals r3.Field<long>("ID")
select new {
ID = r1.Field<long>("ID"),
ParamX = r1.Field<string>("ParamX"),
ParamA = r3.Field<double>("ParamA"),
ParamB = r3.Field<short>("ParamB"),
ParamC = r3.Field<double>("ParamA") * r3.Field<short>("ParamB")
};
var Table4 = new DataTable();
Table4.Columns.Add("ID", typeof(long));
Table4.Columns.Add("ParamX", typeof(string));
Table4.Columns.Add("ParamA", typeof(double));
Table4.Columns.Add("ParamB", typeof(short));
Table4.Columns.Add("ParamC", typeof(double));
You use a loop to execute the query and to insert the rows into the table:
foreach (var x in query)
{
DataRow addedRow = Table4.Rows.Add();
addedRow.SetField("ID", x.ID);
addedRow.SetField("ParamX", x.ParamX);
addedRow.SetField("ParamA", x.ParamA);
addedRow.SetField("ParamB", x.ParamB);
addedRow.SetField("ParamC", x.ParamC);
}
For what it's worth, here's an extension method that allows to create a DataTable from an IEnumerable<anything> via reflection:
public static class Extensions
{
public static DataTable ToDataTable<T>(this IEnumerable<T> data)
{
PropertyDescriptorCollection props =
TypeDescriptor.GetProperties(typeof(T));
DataTable table = new DataTable();
for (int i = 0; i < props.Count; i++)
{
PropertyDescriptor prop = props[i];
table.Columns.Add(prop.Name, prop.PropertyType);
}
object[] values = new object[props.Count];
foreach (T item in data)
{
for (int i = 0; i < values.Length; i++)
{
values[i] = props[i].GetValue(item);
}
table.Rows.Add(values);
}
return table;
}
}
Then you don't need to create or fill the table manually:
DataTable Table4 = query.ToDataTable();

Related

How To Convert 'system.collections.generic.list ' to 'system.data.datatable'

Here i am trying to bind the user list uow.Repository<User>().GetAll().ToList(); to DataTable dt but there is a error saying cannot convert type 'system.collections.generic.list ' to 'system.data.datatable' in line dt = uow.Repository<User>().GetAll().ToList();.
Below is my code
public DataTable GetAllUser1()
{
DataTable dt = new DataTable();
dt = uow.Repository<User>().GetAll().ToList();
return dt;
}
Any Help will be highy appreciated.Thank you
Without much code and mess use Linq to data set:
IEnumerable<DataRow> query = uow.Repository<User>().GetAll().AsEnumerable();
DataTable dt = query.CopyToDataTable<DataRow>();
The CopyToDataTable method uses the following process to create a
DataTable from a query:
1.The CopyToDataTable method clones a DataTable from the source table (a DataTable object that implements the IQueryable interface). The
IEnumerable source has generally originated from a LINQ to DataSet
expression or method query.
2.The schema of the cloned DataTable is built from the columns of the first enumerated DataRow object in the source table and the name of
the cloned table is the name of the source table with the word "query"
appended to it.
3.For each row in the source table, the content of the row is copied into a new DataRow object, which is then inserted into the cloned
table. The RowState and RowError properties are preserved across the
copy operation. An ArgumentException is thrown if the DataRow objects
in the source are from different tables.
4.The cloned DataTable is returned after all DataRow objects in the input queryable table have been copied. If the source sequence does
not contain any DataRow objects, the method returns an empty
DataTable.
You can use following method to convert List to DataTable
public DataTable GetAllUser1()
{
DataTable dt = new DataTable();
dt = ToDataTable(uow.Repository<User>().GetAll().ToList());
return dt;
}
public DataTable ToDataTable<T>(List<T> items)
{
DataTable dataTable = new DataTable(typeof(T).Name);
//Get all the properties
PropertyInfo[] Props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (PropertyInfo prop in Props)
{
//Setting column names as Property names
dataTable.Columns.Add(prop.Name);
}
foreach (T item in items)
{
var values = new object[Props.Length];
for (int i = 0; i < Props.Length; i++)
{
//inserting property values to datatable rows
values[i] = Props[i].GetValue(item, null);
}
dataTable.Rows.Add(values);
}
//put a breakpoint here and check datatable
return dataTable;
}
You can use the following method to convert list to DataTable
public DataTable GetAllUser1()
{
DataTable dt = new DataTable();
dt =ToDataTable(uow.Repository<User>().GetAll().ToList());
return dt;
}
public static DataTable ToDataTable<T>(this IList<T> data)
{
PropertyDescriptorCollection properties =
TypeDescriptor.GetProperties(typeof(T));
DataTable table = new DataTable();
foreach (PropertyDescriptor prop in properties)
table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
foreach (T item in data)
{
DataRow row = table.NewRow();
foreach (PropertyDescriptor prop in properties)
row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
table.Rows.Add(row);
}
return table;
}
DataTable dt = new DataTable();
dt = uow.Repository<User>().GetAll().ToList();
It doesn't work like that. You should use the DataTable methods to fill it. Providing an example would provide better understanding. For example; the User class contains these properties;
public class User
{
public int Id { get; set; }
public string Name { get; set; }
}
You should specify the columns for DataTable;
DataTable dt = new DataTable();
dt.Columns.Add("Id");
dt.Columns.Add("Name");
Now, you can add rows in a simple loop;
var userList = uow.Repository<User>().GetAll().ToList();
DataTable dt = new DataTable();
dt.Columns.Add("Id");
dt.Columns.Add("Name");
foreach (var user in userList)
{
var newRow = dt.NewRow();
newRow["Id"] = user.Id;
newRow["Name"] = user.Name;
dt.Rows.Add(newRow);
}
Also, you can provide a solution dynamically by getting the properties and accessing them using Reflection.
You can not directly convert list to Data Table
instead you can build up a generic function. mentioned in below code. You need to convert your list to build up Data Table Rows and Columns.
public DataTable ConvertTODataTable<T>(IList<T> data)// T is any generic type
{
PropertyDescriptorCollection props = TypeDescriptor.GetProperties(typeof(T));
DataTable table = new DataTable();
for (int i = 0; i < props.Count; i++)
{
PropertyDescriptor prop = props[i];
table.Columns.Add(prop.Name, prop.PropertyType);
}
object[] values = new object[props.Count];
foreach (T item in data)
{
for (int i = 0; i < values.Length; i++)
{
values[i] = props[i].GetValue(item);
}
table.Rows.Add(values);
}
return table;
}

How to populate DataTable with anonymous LINQ result

I have the following LINQ query:
var timesheets = from timesheet in entities.Timesheets
join timesheetTask in entities.Timesheet_Task on timesheet.Id equals timesheetTask.Timesheet_Id
join task in entities.Tasks on timesheetTask.Task_Id equals task.Id
join project in entities.Projects on task.Project_Id equals project.Id
join department in entities.Departments on project.Department_Id equals department.Id
where timesheet.Employee_Id == employeeId
select new
{
date = timesheet.Date,
taskName = task.Name,
projectName = project.Name,
projectDesc = project.Description,
departmentName = department.Name,
taskEstimatedHours = task.Estimated_Hours,
timesheetHours = timesheetTask.Hours
};
How can I put these results into a DataTable which I can then bind to a DataGridView control?
This is what I'm currently doing:
table.Columns.Add("date");
table.Columns.Add("taskName");
table.Columns.Add("projectName");
table.Columns.Add("projectDesc");
table.Columns.Add("departmentName");
table.Columns.Add("taskEstimatedHours");
table.Columns.Add("timesheetHours");
foreach (var item in timesheets)
{
table.Rows.Add(item.date, item.taskName, item.projectName,
item.projectDesc, item.departmentName, item.taskEstimatedHours,
item.timesheetHours);
}
}
Update: Here is my updated code:
DataTable table = new DataTable();
using (PTMS_DataEntities entities = new PTMS_DataEntities())
{
var timesheets = from timesheet in entities.Timesheets
join timesheetTask in entities.Timesheet_Task on timesheet.Id equals timesheetTask.Timesheet_Id
join task in entities.Tasks on timesheetTask.Task_Id equals task.Id
join project in entities.Projects on task.Project_Id equals project.Id
join department in entities.Departments on project.Department_Id equals department.Id
where timesheet.Employee_Id == employeeId
select new
{
date = timesheet.Date,
taskName = task.Name,
projectName = project.Name,
projectDesc = project.Description,
departmentName = department.Name,
taskEstimatedHours = task.Estimated_Hours,
timesheetHours = timesheetTask.Hours
};
table.Columns.Add("date", typeof(DateTime));
table.Columns.Add("taskName", typeof(string));
table.Columns.Add("projectName", typeof(string));
table.Columns.Add("projectDesc", typeof(string));
table.Columns.Add("departmentName", typeof(string));
table.Columns.Add("taskEstimatedHours", typeof(int));
table.Columns.Add("timesheetHours", typeof(int));
List<DataRow> list = new List<DataRow>();
foreach (var item in timesheets)
{
//table.Rows.Add(item.date, item.taskName, item.projectName,
// item.projectDesc, item.departmentName, item.taskEstimatedHours,
// item.timesheetHours);
var row = table.NewRow();
row.SetField<DateTime>("date", item.date);
row.SetField<string>("taskName", item.taskName);
row.SetField<string>("projectName", item.projectName);
row.SetField<string>("projectDesc", item.projectDesc);
row.SetField<string>("departmentName", item.departmentName);
row.SetField<int>("taskEstimatedHours", item.taskEstimatedHours);
row.SetField<int>("timesheetHours", item.timesheetHours);
list.Add(row);
}
table = list.CopyToDataTable();
}
Here is the SQL query I tested in SSMS (which should be the equivalent of the LINQ query):
SELECT dbo.Department.Name, dbo.Task.Name AS Expr1, dbo.Task.Estimated_Hours, dbo.Timesheet.Date, dbo.Project.Name AS Expr2, dbo.Project.Description,
dbo.Timesheet_Task.Date AS Expr3
FROM dbo.Department INNER JOIN
dbo.Project ON dbo.Department.Id = dbo.Project.Department_Id INNER JOIN
dbo.Task ON dbo.Project.Id = dbo.Task.Project_Id INNER JOIN
dbo.Timesheet_Task ON dbo.Task.Id = dbo.Timesheet_Task.Task_Id INNER JOIN
dbo.Timesheet ON dbo.Timesheet_Task.Timesheet_Id = dbo.Timesheet.Id
If you really want to populate DataTable:
// your query
var timesheets = ...
// design table first
DataTable table = new DataTable();
table.Columns.Add(new DataColumn
{
ColumnName = "TaskName",
DataType = typeof(String);
});
...
List<DataRow> list = new List<DataRow>();
foreach (var t in timesheets)
{
var row = table.NewRow();
row.SetField<string>("TaskName", t.taskName); // extension method from System.Data.DataSetExtensions.dll
...
list.Add(row);
}
DataTable table = list.CopyToDataTable(); // extension method too
Or more LINQ way:
timesheets
.Select(t =>
{
var row = table.NewRow();
...
return row;
})
.CopyToDataTable();
Or in same query syntax. Implement a method:
static DataRow NewRow(DataRow row, string taskName, ....)
{
...
}
Then query itself:
(from ...
where ...
select NewRow(table.NewRow(), task.Name, ...)
).CopyToDataTable();
Call .ToList().
The resulting List<T> can also be bound to a DataGridView, and is easier to work with than a DataTable.
I'm using FastMember for this purpose. It uses IL instead of reflection (much faster) to iterate over all of the property and field values automatically. Code sample from the site:
IEnumerable<SomeType> data = ...
var table = new DataTable();
using(var reader = ObjectReader.Create(data))
{
table.Load(reader);
}

Remove columns from datatable

I have a datatable with 20 columns. But i don't need all the columns for the current processing except 5. So i did the below to remove the columns
List<string> clmnames = new List<string>() { "clm6","clm7"..."clm20" };
foreach (string dcName in clmnames)
{
TestAndRemoveColumn(dcName, ds.Tables["TestTable"]);
}
private void TestAndRemoveColumn(string dcName,DataTable datatable)
{
DataColumnCollection dcCollection = datatable.Columns;
if (dcCollection.Contains(dcName))
{
dcCollection.Remove(dcName);
}
}
Instead of looping through the 15 times is there any other way to achieve using easily ?
try this
List<string> listtoRemove = new List<string> { "CLM6", "CLM7", "CLM20" };
for (int i = dt.Columns.Count - 1; i >= 0; i--)
{
DataColumn dc = dt.Columns[i];
if (listtoRemove.Contains(dc.ColumnName.ToUpper()))
{
dt.Columns.Remove(dc);
}
}
In some scenarios may be preferable to clone DataTable and specify columns to copy.
DataView view = new DataView(table);
DataTable table2 = view.ToTable(false, "clm6", "clm7", ...);
Problem seems to be in your code, you get all the comlumns from the datatable then remove the columns but you have not again assign the columns to that datatable
first you get columns
DataColumnCollection dcCollection = datatable.Columns; // get cols
if (dcCollection.Contains(dcName))
{
dcCollection.Remove(dcName); /// remove columns
// but you have not updated you datatable columns.
here should be something like this
datatable.Columns = dcCollection; /// i don't know this will work or not check it
}
Try this
DataTable dt;
dt.Columns.Remove("columnName");
dt.Columns.RemoveAt(columnIndex);
you can use them as
private void TestAndRemoveColumn(string dcName,DataTable datatable)
{
DataTable dt = datatable;
dt.Columns.Remove("dcName");
}
Alternatively you can select only the required columns(Only 5 in your case) like this.
DataTable dt = new DataTable();
dt.Columns.Add("ID");
dt.Columns.Add("Value");
dt.Rows.Add("1", "One");
dt.Rows.Add("2", "Two");
string[] arr= new string[1];
arr[0] = "Value";//add the required columns to the array
//return only the required columns.
DataTable dt2 = dt.DefaultView.ToTable(false, arr);
You could join the columns you want remove with the available columns:
var keepColNames = new List<String>(){ "clm5" };
var allColumns = tbl.Columns.Cast<DataColumn>();
var allColNames = allColumns.Select(c => c.ColumnName);
var removeColNames = allColNames.Except(keepColNames);
var colsToRemove = from r in removeColNames
join c in allColumns on r equals c.ColumnName
select c;
while (colsToRemove.Any())
tbl.Columns.Remove(colsToRemove.First());
If you know that you only have few remaining columns, you could add the column(s):
var colsToAdd = (from keepCol in keepColNames
join col in tbl.Columns.Cast<DataColumn>()
on keepCol equals col.ColumnName
select col).ToList();
tbl.Columns.Clear();
foreach (var colToAdd in colsToAdd)
tbl.Columns.Add(colToAdd);

DataTable Join or Merge

I have 3 Data tables populated with a dataset and table adapters/ binding sources and i need to run a Join query or find another way to get specific data. (the dataset contains each table listed)
Tables:
Product Table:
Prod_ID Name
1 tv
2 couch
Consumer Table:
Con_Id Name City
----------------------
1 Gray New York
2 Joe Chicago
3 Steve Madison
Transactions Table
Tran_Id Con_ID Prod_ID Price
-------------------------------------
1 2 1 900
2 1 2 300
Given a product name i need to populate a table with each distinct city and how much that product has sold for in that city (add all prices for that product to any consumer in a given city)
I am really stumped and cant find a way. (i have tried alot)
Please help and thank you!
Nudiers approach so far:
DataRelation relation = null;
DataColumn table1Column = null;
DataColumn table2Column = null;
DataColumn table3Column = null;
table1Column = tlobergeDataSet.Tb_Product.Columns[0];
table2Column = tlobergeDataSet.Tb_Transactions.Columns[3];
table3Column = tlobergeDataSet.Tb_Consumer.Columns[0];
relation = new DataRelation("relation", table1Column, table2Column);
tlobergeDataSet.Relations.Add(relation);
public DataTable MergeTables(DataTable dtFirst, DataTable dtSecond, string CommonColumn)
{
DataTable dtResults = dtFirst.Clone();
int count = 0;
for (int i = 0; i < dtSecond.Columns.Count; i++)
{
if (!dtFirst.Columns.Contains(dtSecond.Columns[i].ColumnName))
{
dtResults.Columns.Add(dtSecond.Columns[i].ColumnName, dtSecond.Columns[i].DataType);
count++;
}
}
DataColumn[] columns = new DataColumn[count];
int j = 0;
for (int i = 0; i < dtSecond.Columns.Count; i++)
{
if (!dtFirst.Columns.Contains(dtSecond.Columns[i].ColumnName))
{
columns[j++] = new DataColumn(dtSecond.Columns[i].ColumnName, dtSecond.Columns[i].DataType);
}
}
dtResults.BeginLoadData();
foreach (DataRow dr in dtFirst.Rows)
{
dtResults.Rows.Add(dr.ItemArray);
}
foreach (DataRow dr in dtSecond.Rows)
{
foreach (DataRow dr1 in dtResults.Rows)
{
if (dr1[CommonColumn].ToString().Equals(dr[CommonColumn].ToString()))
{
foreach (DataColumn c in columns)
{
dr1[c.ColumnName] = dr[c.ColumnName];
}
}
}
}
dtResults.EndLoadData();
return dtResults;
}
try with this.
DataRelation relation = null;
DataColumn table1Column = null;
DataColumn table2Column = null;
//retrieve column
table1Column = ds.Tables("Table1").Columns(0);
table2Column = ds.Tables("table2").Columns(0);
//relating tables
relation = new DataRelation("relation", table1Column, table2Column);
//assign relation to dataset
ds.Relations.Add(relation);
You can only relate two tables in a DataRelation object and to access the data from
the dataset is straightforward because the data has been already related.
DataRelation relation = null;
DataColumn table1Column = null;
DataColumn table2Column = null;
DataColumn table3Column = null;
table1Column = tlobergeDataSet.Tb_Product.Columns[0];
table2Column = tlobergeDataSet.Tb_Transactions.Columns[2];
table2Column1 = tlobergeDataSet.Tb_Transactions.Columns[1];
table3Column = tlobergeDataSet.Tb_Consumer.Columns[0];
relation = new DataRelation("relation", table1Column, table2Column);
tlobergeDataSet.Relations.Add(relation);
relation = new DataRelation("relation1", table3Column , table2Column1);
tlobergeDataSet.Relations.Add(relation);
In LINQ, you can join the tables to find the data you want with syntax like so:
from a in keyTable
join b in anotherTable on a.Key equals b.Key
join c in aThirdTable on a.Key equals c.Key
select new
{
// Anonymous Object Properties using identifier a, b, and c to get data
};
You should be able to take that snippet and generate a linq query that will generate an anonymous object containing the specific data representation that you need.

Inner join of DataTables in C#

Let T1 and T2 are DataTables with following fields
T1(CustID, ColX, ColY)
T2(CustID, ColZ)
I need the joint table
TJ (CustID, ColX, ColY, ColZ)
How this can be done in C# code in a simple way? Thanks.
If you are allowed to use LINQ, take a look at the following example. It creates two DataTables with integer columns, fills them with some records, join them using LINQ query and outputs them to Console.
DataTable dt1 = new DataTable();
dt1.Columns.Add("CustID", typeof(int));
dt1.Columns.Add("ColX", typeof(int));
dt1.Columns.Add("ColY", typeof(int));
DataTable dt2 = new DataTable();
dt2.Columns.Add("CustID", typeof(int));
dt2.Columns.Add("ColZ", typeof(int));
for (int i = 1; i <= 5; i++)
{
DataRow row = dt1.NewRow();
row["CustID"] = i;
row["ColX"] = 10 + i;
row["ColY"] = 20 + i;
dt1.Rows.Add(row);
row = dt2.NewRow();
row["CustID"] = i;
row["ColZ"] = 30 + i;
dt2.Rows.Add(row);
}
var results = from table1 in dt1.AsEnumerable()
join table2 in dt2.AsEnumerable() on (int)table1["CustID"] equals (int)table2["CustID"]
select new
{
CustID = (int)table1["CustID"],
ColX = (int)table1["ColX"],
ColY = (int)table1["ColY"],
ColZ = (int)table2["ColZ"]
};
foreach (var item in results)
{
Console.WriteLine(String.Format("ID = {0}, ColX = {1}, ColY = {2}, ColZ = {3}", item.CustID, item.ColX, item.ColY, item.ColZ));
}
Console.ReadLine();
// Output:
// ID = 1, ColX = 11, ColY = 21, ColZ = 31
// ID = 2, ColX = 12, ColY = 22, ColZ = 32
// ID = 3, ColX = 13, ColY = 23, ColZ = 33
// ID = 4, ColX = 14, ColY = 24, ColZ = 34
// ID = 5, ColX = 15, ColY = 25, ColZ = 35
I wanted a function that would join tables without requiring you to define the columns using an anonymous type selector, but had a hard time finding any. I ended up having to make my own. Hopefully this will help anyone in the future who searches for this:
private DataTable JoinDataTables(DataTable t1, DataTable t2, params Func<DataRow, DataRow, bool>[] joinOn)
{
DataTable result = new DataTable();
foreach (DataColumn col in t1.Columns)
{
if (result.Columns[col.ColumnName] == null)
result.Columns.Add(col.ColumnName, col.DataType);
}
foreach (DataColumn col in t2.Columns)
{
if (result.Columns[col.ColumnName] == null)
result.Columns.Add(col.ColumnName, col.DataType);
}
foreach (DataRow row1 in t1.Rows)
{
var joinRows = t2.AsEnumerable().Where(row2 =>
{
foreach (var parameter in joinOn)
{
if (!parameter(row1, row2)) return false;
}
return true;
});
foreach (DataRow fromRow in joinRows)
{
DataRow insertRow = result.NewRow();
foreach (DataColumn col1 in t1.Columns)
{
insertRow[col1.ColumnName] = row1[col1.ColumnName];
}
foreach (DataColumn col2 in t2.Columns)
{
insertRow[col2.ColumnName] = fromRow[col2.ColumnName];
}
result.Rows.Add(insertRow);
}
}
return result;
}
An example of how you might use this:
var test = JoinDataTables(transactionInfo, transactionItems,
(row1, row2) =>
row1.Field<int>("TransactionID") == row2.Field<int>("TransactionID"));
One caveat: This is certainly not optimized, so be mindful when getting to row counts above 20k. If you know that one table will be larger than the other, try to put the smaller one first and the larger one second.
This is my code. Not perfect, but working good. I hope it helps somebody:
static System.Data.DataTable DtTbl (System.Data.DataTable[] dtToJoin)
{
System.Data.DataTable dtJoined = new System.Data.DataTable();
foreach (System.Data.DataColumn dc in dtToJoin[0].Columns)
dtJoined.Columns.Add(dc.ColumnName);
foreach (System.Data.DataTable dt in dtToJoin)
foreach (System.Data.DataRow dr1 in dt.Rows)
{
System.Data.DataRow dr = dtJoined.NewRow();
foreach (System.Data.DataColumn dc in dtToJoin[0].Columns)
dr[dc.ColumnName] = dr1[dc.ColumnName];
dtJoined.Rows.Add(dr);
}
return dtJoined;
}
this function will join 2 tables with a known join field, but this cannot allow 2 fields with the same name on both tables except the join field, a simple modification would be to save a dictionary with a counter and just add number to the same name filds.
public static DataTable JoinDataTable(DataTable dataTable1, DataTable dataTable2, string joinField)
{
var dt = new DataTable();
var joinTable = from t1 in dataTable1.AsEnumerable()
join t2 in dataTable2.AsEnumerable()
on t1[joinField] equals t2[joinField]
select new { t1, t2 };
foreach (DataColumn col in dataTable1.Columns)
dt.Columns.Add(col.ColumnName, typeof(string));
dt.Columns.Remove(joinField);
foreach (DataColumn col in dataTable2.Columns)
dt.Columns.Add(col.ColumnName, typeof(string));
foreach (var row in joinTable)
{
var newRow = dt.NewRow();
newRow.ItemArray = row.t1.ItemArray.Union(row.t2.ItemArray).ToArray();
dt.Rows.Add(newRow);
}
return dt;
}
I tried to do this in next way
public static DataTable JoinTwoTables(DataTable innerTable, DataTable outerTable)
{
DataTable resultTable = new DataTable();
var innerTableColumns = new List<string>();
foreach (DataColumn column in innerTable.Columns)
{
innerTableColumns.Add(column.ColumnName);
resultTable.Columns.Add(column.ColumnName);
}
var outerTableColumns = new List<string>();
foreach (DataColumn column in outerTable.Columns)
{
if (!innerTableColumns.Contains(column.ColumnName))
{
outerTableColumns.Add(column.ColumnName);
resultTable.Columns.Add(column.ColumnName);
}
}
for (int i = 0; i < innerTable.Rows.Count; i++)
{
var row = resultTable.NewRow();
innerTableColumns.ForEach(x =>
{
row[x] = innerTable.Rows[i][x];
});
outerTableColumns.ForEach(x =>
{
row[x] = outerTable.Rows[i][x];
});
resultTable.Rows.Add(row);
}
return resultTable;
}
Note that if you have a DataSet, you will need to steal the table from the Dataset with dataSet.Table[0]

Categories

Resources