I have defined a dataTable Like this
DataTable dtFinal = new DataTable();
dtFinal.Columns.Add("AVNR", typeof(int));
dtFinal.Columns.Add("Substation", typeof(string));
dtFinal.Columns.Add("ColumnTitle", typeof(string));
dtFinal.Columns.Add("S6_NAME", typeof(string));
dtFinal.Columns.Add("Voltage", typeof(string));
dtFinal.Columns.Add("Wert", typeof(decimal));
and I make a join between two tables to have a result set
var results = from table1 in dtTimeListTable.AsEnumerable()
join table2 in readyDataTable.AsEnumerable() on (decimal)table1["Avnr"] equals (int)table2["Avnr"]
select new
{
AVNR = (int)table2["AVNR"],
Substation = (string)table2["Substation"],
ColumnTitle = (string)table2["ColumnTitle"],
S6_NAME = (string)table2["S6_NAME"],
Voltage = (string)table2["Voltage"],
Wert = (decimal)table1["Wert"]
};
to fill datatable up I do the following:
dtFinal.Rows.Add(results.ToArray());
but I'll get a error liek this
input array is longer than the number of columns in this table
both datatable have 6 columns, what could be the problem?
DataRowCollection.Add is a method to add a single DataRow but you are trying to add all rows.
You need a loop:
foreach(var x in query)
dtFinal.Rows.Add(x.AVNR, x.Substation, x.ColumnTitle, x.S6_NAME, x.Voltage, x.Wert);
You could build the object[] for each DataRow also in this way:
var joinedRows = from table1 in dtTimeListTable.AsEnumerable()
join table2 in readyDataTable.AsEnumerable() on (decimal) table1["Avnr"] equals (int) table2["Avnr"]
select new { r1 = table1, r2 = table2 };
foreach (var x in joinedRows)
{
object[] fields =
{
x.r2.Field<int>("AVNR"), x.r2.Field<string>("Substation"), x.r2.Field<string>("ColumnTitle"),
x.r2.Field<int>("S6_NAME"), x.r2.Field<string>("Voltage"), x.r1.Field<decimal>("Wert"),
};
dtFinal.Rows.Add(fields);
}
Related
I have created an application where the user can specify queries to databases, maybe even different databases. They would like to have functionality to join the two query results (stored in DataTables) together on user-specified criteria.
The user specifies the join criteria in an XML settings file like this:
<Join Name="join_example" TableAName="tbl_example1" TableBName="tbl_example2" Expression="a.ID == b.ID" />
So far i have converted the DataTables to List of dynamic so the column names are now properties, but I am getting the following error when trying to create the DynamicExpression using those properties:
{"No property or field 'ID' exists in type 'List`1'"}
Any ideas how i can create the dynamic expression? I am open to other ways to perform the join, but would like for the user to be able to use the syntax specified in the XML. Here is my code that is generating the error.
List<dynamic> TableA = ToDynamicList(DataTableA);
List<dynamic> TableB = ToDynamicList(DataTableB);
ParameterExpression paramA = System.Linq.Expressions.Expression.Parameter(TableA.GetType(), "a");
ParameterExpression paramB = System.Linq.Expressions.Expression.Parameter(TableB.GetType(), "b");
Expression Exp = System.Linq.Dynamic.DynamicExpression.Parse(new ParameterExpression[] { paramA, paramB }, TableA.GetType(), this.Expression, new List<dynamic>[] { TableA, TableB });
You don't need to cast the results from tables, you just need to merge them. Here is a linqpad example:
void Main()
{
var dt1 = new DataTable();
dt1.Columns.Add("col1", typeof(string));
dt1.Columns.Add("col2", typeof(int));
var dt2 = new DataTable();
dt2.Columns.Add("col1", typeof(string));
dt2.Columns.Add("col2", typeof(int));
var row = dt1.NewRow();
row["col1"] = "one";
row["col2"] = 1;
dt1.Rows.Add(row);
row = dt1.NewRow();
row["col1"] = "two";
row["col2"] = 2;
dt1.Rows.Add(row);
row = dt2.NewRow();
row["col1"] = "three";
row["col2"] = 3;
dt2.Rows.Add(row);
row = dt2.NewRow();
row["col1"] = "four";
row["col2"] = 4;
dt2.Rows.Add(row);
var dtMerged = dt1.AsEnumerable().CopyToDataTable(); // Note: CopyToDataTable requirs that there are rows. must trap for empty table
dtMerged.Merge(dt2.AsEnumerable().CopyToDataTable(), true, MissingSchemaAction.Add);
dtMerged.Dump();
}
I have the following LINQ query :
var groupedData = from b in loans.AsEnumerable()
group b by b.Field<int>("loan_code") & b.Field<int>("emp_num")
into f
select f.CopyToDataTable();
I want to select f and in addition to that the summation of Tot field and copy the result in data table .how to do that?
Get required data
var groupedData = from r in loans.AsEnumerable()
group r by new {
LoanCode = r.Field<int>("loan_code"),
EmpNum = r.Field<int>("emp_num")
} into g
select new {
g.Key.LoanCode,
g.Key.EmpNum,
Tot = g.Sum(r => r.Field<int>("Tot")) // assume integer
};
Then use custom CopyToDataTable method (which works for types that don't implement DataRow) to convert them to DataTable. Or you can build DataTable manually:
DataTable dt = new DataTable();
dt.Columns.Add("loan_code", typeof(int));
dt.Columns.Add("emp_num", typeof(int));
dt.Columns.Add("Tot", typeof(int));
foreach(var data in groupedData)
dt.Rows.Add(data.LoanCode, data.EmpNum, data.Tot);
I have the same issue as here is LINQ join two DataTables
but my datatables are made on runtime like
DataTable dtTML = (DataTable)JsonConvert.DeserializeObject(Convert.ToString(data.Json.Args[0]["TML"]), (typeof(DataTable)));
the solution that someone gave is fine but I am getting error on datarows2 at
select dtResult.LoadDataRow(new object[]
{
dataRows2.Field<int>("stock") // here is error : does not exist in current context
}
while dataRows1.Field(s) are fine
I can't see what's wrong with this approach :
DataTable dt1 = new DataTable();
dt1.Columns.Add("PK", typeof(int));
dt1.Columns.Add("Data1", typeof(int));
DataTable dt2 = new DataTable();
dt2.Columns.Add("FK", typeof(int));
dt2.Columns.Add("Data2", typeof(int));
dt2.Rows.Add(1, 5000);
dt1.Rows.Add(1, 1000);
var Result = (from r1 in dt1.AsEnumerable()
join r2 in dt2.AsEnumerable()
on r1["PK"] equals r2["FK"]
select new
{
A = r1.Field<int>("Data1"),
B = r2.Field<int>("Data2"),
// choose more columns if any
}).ToList();
You can do whatever you want using it. If you need the result to be a Datatable , just use this method [ ListToDataTable ] to convert List to DataTable:
public static DataTable ListToDataTable<T>(List<T> items)
{
System.ComponentModel.PropertyDescriptorCollection properties =
System.ComponentModel.TypeDescriptor.GetProperties(typeof(T));
DataTable table = new DataTable();
foreach (System.ComponentModel.PropertyDescriptor prop in properties)
table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
foreach (T item in items)
{
DataRow row = table.NewRow();
foreach (System.ComponentModel.PropertyDescriptor prop in properties)
row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
table.Rows.Add(row);
}
return table;
have a Dataset Ds1 and dataset Ds2 , DS1 has Product_ID, product information and ds2 has Product_ID, product_type.
for the matching product_id, I want to add the Product_tye column from ds2 to ds1 .
Note: Product_id is not primary key in ds 1, the result set has many products with same product_id. In ds 2, product_id is unique. also, those datatbles are from two different databases on different servers and has different credentials , so cant use sql joins.
I tried to use linq to acheive this, but not getting the desired output, please correct me if i am mising something .
DataTable dt1 = new DataTable();
DataTable dt2 = new DataTable();
//After both the datatble has values, using linq to add datatble columsn,
DataTable result = (from t1 in dt1.AsEnumerable()
join t2 in dt2.AsEnumerable() on t1.Field<string>("productID") equals t2.Field<string>("productID")
select t1).CopyToDataTable();
Selecting both tables
DataTable result = (from t1 in dt1.AsEnumerable()
join t2 in dt2.AsEnumerable() on t1.Field<string>("productID")
equals t2.Field<string>("productID")
select new {t1,t2}
).CopyToDataTable();
OR Selecting selected columns
DataTable result = (from t1 in dt1.AsEnumerable()
join t2 in dt2.AsEnumerable() on t1.Field<string>("productID")
equals t2.Field<string>("productID")
select new {
productId = t1.productID,
col2 = t1.col2,...,
productType = t2.pruductType
).CopyToDataTable();
NOTE: I think productID type should be int type so replace string with int in that case
I have just created you a simple example, what you have to do is to change column names from my code, with your own:
DataTable table1 = new DataTable();
DataTable table2 = new DataTable();
table1.Columns.Add("id", typeof(int));
table1.Columns.Add("name", typeof(string));
table2.Columns.Add("id", typeof(int));
table2.Columns.Add("age", typeof(int));
table1.Rows.Add(1, "mitja");
table1.Rows.Add(2, "sandra");
table1.Rows.Add(3, "nataška");
table2.Rows.Add(1, 31);
table2.Rows.Add(3, 24);
table2.Rows.Add(4, 46);
DataTable targetTable = table1.Clone();
//create new column
targetTable.Columns.Add("age");
var results = from t1 in table1.AsEnumerable()
join t2 in table2.AsEnumerable() on t1.Field<int>("id") equals t2.Field<int>("id")
select new
{
ID = (int)t1["id"],
NAME = (string)t1["name"],
AGE = (int)t2["age"]
};
foreach (var item in results)
targetTable.Rows.Add(item.ID, item.NAME, item.AGE);
Be careful on defining type of variables (int, string, ...) in any case!!!
Hope it helps.
Let's say I have two DataTables DT1 and DT2 with a single row.
DT1 has 3 columns: Col1, Col2, and Col3
and
DT2 has 2 columns: ColA, ColB.
Is it possible to join these two DataTables horizontally so I get Col1, Col2, Col3, ColA, and ColB?
I thin you have to add new columns and copy data either in third table or in one of the existing table
DataTable dt1 = new DataTable();
dt1.Columns.Add("col1", typeof(string));
dt1.Columns.Add("col2", typeof(string));
dt1.Columns.Add("col3", typeof(string));
DataTable dt2 = new DataTable();
dt2.Columns.Add("cola", typeof(string));
dt2.Columns.Add("colb", typeof(string));
object[] row = {'1', '2', '3'};
dt1.Rows.Add(row);
object[] row1 = { 'a', 'b' };
dt2.Rows.Add(row1);
// Create columns in dt1
dt1.Columns.Add("cola", typeof(string));
dt1.Columns.Add("colb", typeof(string));
// Copy data from dt2
dt1.Rows[0]["cola"] = dt2.Rows[0]["cola"];
dt1.Rows[0]["colb"] = dt2.Rows[0]["colb"];
So long as you simply want a collection you can bind to you can do the following:
var results = from rs1 in table1.Rows.Cast<DataRow>()
join rs2 in table2.Rows.Cast<DataRow>() on rs1.Field<int>("col1") equals rs2.Field<int>("colA")
select new { col1 = rs1.Field<int>("col1"), col2 = rs1.Field<string>("col3"), col3 = rs1.Field<string>("col3"), colA = rs1.Field<int>("colA"), colB = rs1.Field<string>("colB") };
You would not get a DataTable but an IEnumerable<T> collection of anonymous type objects as defined in the select statement. Obvoiusly i have just guessed the join criteria and the data type of the columns so you would have to specify those as appropriate for your actual data.