How to select all columns in LINQ Datatable join? - c#

var collection = from t1 in dt1.AsEnumerable()
join t2 in dt2.AsEnumerable()
on t1["id"] equals t2["id"]
select new { Name = t1["name"], Group = t2["group"] };
I want to select all columns of both table like join in SQL Server inner join query.
In Addition
How can i convert whole result of both tables to data-table?

var collection = from t1 in dt1.AsEnumerable()
join t2 in dt2.AsEnumerable()
on t1["id"] equals t2["id"]
select new { T1 = t1, T2 = t2 };
then...
EDIT:
Something along those lines
//clone dt1, copies all the columns to newTable
DataTable newTable = dt1.Clone();
//copies all the columns from dt2 to newTable
foreach(var c in dt2.Columns)
newTable.Columns.Add(c);
//now newTable has all the columns from the original tables combined
//iterates over collection
foreach (var item in collection) {
//creates newRow from newTable
DataRow newRow = newTable.NewRow();
//iterate the columns, gets values from either original table if column name is there
foreach(var c in newTable.Columns)
newRow[c.ColumnName] = item.T1.ContainsColumn(c.ColumnName) ? item.T1[c.ColumnName] : item.T2[c.ColumnName];
newTable.Rows.Add(newRow);
}
This will work. But if dt1 and dt2 share multiple columns with the exact same name, you might have some loss of data.

While you can't expand them to columns, you can simply return the entities. Eg:
select new { CTLJCRJOB, CTLRFDSTM }
If you need it flattened, then you will have to write out the mapping yourself, but will still be very trivial.
Referenced from:
Select All columns for all tables in join + linq join
ou have to specify each manually if you want to project into a flattened type. Your other option is to just have your combined type contain both objects, and the objects will naturally bring along their properties.
select new
{
Object1 = object1,
Object2 = output
};
And you would work with it like myObj.Object1.Property1, myObj.Object2.Property4, etc.
One final option that still involves some manual work is to define an appropriate type and have a constructor or a builder method that does the work of segmenting out your object properties into a flattened type. You still perform the manual mapping, but you isolate it from your query logic.
select new CombinedType(object1, output);
//or
select builder.GetCombinedType(object1, output);
Referenced From
Select all columns after JOIN in LINQ

var collection = (from t1 in dt1.AsEnumerable()
join t2 in dt2.AsEnumerable()
on t1 ["id"] equals t2 ["id"]
select new { Name = t1 ["name"], Group = t2 ["group"] }).ToList() ;
Hope this will help

Related

C# LINQ list select columns dynamically from a joined dataset

I'm using LINQ to join 2 datatables:
var JoinResult = (from p in WZdt.AsEnumerable()
join t in WZIdt.AsEnumerable()
on p.Field<string>("ID") equals t.Field<string>("ID")
select new
{
p,
t
}).ToList();
WZdt and WZIdt are DataTables. Normally, when wanted to specify columns I would write something like this:
var JoinResult = (from p in WZdt.AsEnumerable()
join t in WZIdt.AsEnumerable()
on p.Field<string>("ID") equals t.Field<string>("ID")
select new
{
FileNo = p.Field<string>("FileNo"),
Title = p.Field<string>("Title"),
M1 = t.Field<int?>("M1"),
RecCount = t.Field<int?>("RecCount")
}).ToList();
But those source datatables are created dynamically based on some logic, so they can differ when it comes to Columns they have. I would like to apply similiar logic to the select part of LINQ, but I don't know how. Can I construct array of columns somehow, like [p.FileNo, p.Title, t.M1, t.RecCount] ?
Or any other way?

Join Two DataTables (Some Rows Match some Don't)

I have two Data Tables: T1 and T2
T1 and T2 both have a Column Registration, but T2 doesn't have all the same Rows as T1.
I have to combine the Two Tables such that if the Registration Number is same get columns from T2, if not show Blank, but I need ALL ROWS FROM T1, (IF MATCH OR NOT).
I tried this but I only get matching Rows:
var results = from table1 in T1
join table2 in T2
on (String)table1["Registration"] equals (String)table2["Registration"]
select new
{
Registration = (String)table1["Registration"],
DistanceInKM = (decimal)table1["DistanceInKM"],
TotalDistanceTravelledKM = (Double)table2["TotalDistanceTravelledKM"]
};
You're performing an inner join, which only shows rows that exist on both sides.
Try using a left outer join instead:
var results = (from table1 in T1.AsEnumerable()
join tmp in T2.AsEnumerable() on table1["Registration"] equals tmp["Registration"] into grp
from table2 in grp.DefaultIfEmpty()
select new
{
Registration = (String)table1["Registration"],
DistanceInKM = (decimal)table1["DistanceInKM"],
TotalDistanceTravelledKM = (table2 == null ? (double?)null : (Double)table2["TotalDistanceTravelledKM"])
};

Linq to SQL Join IQueryable Set Certain Property

Is this possible?
Let's say I had a simple IQueryable join like below:
var x = from t1 in Repo.GetThing1()
join t2 in Repo.GetThing2() on t1.Key equals t2.Key
select t1).ToList();
But let's there is a field on t1 that I want to set with t2. However I don't want to re-map all the fields from t1, I just want the ability to map that particular field in t1 from t2...
Sure:
var query = from t1 in Repo.GetThing1()
join t2 in Repo.GetThing2() on t1.Key equals t2.Key
select new { Existing = t1, NewValue = t2.SomeField };
var list = query.ToList();
foreach (var pair in list)
{
pair.Existing.SomeField = pair.NewValue;
}
(Then you can do whatever you want, of course.)

Help with querying a DataTable using LINQ

Suppose I have this initial code:
DataTable table = new DataTable();
table.Columns.Add("column1", typeof(int));
table.Columns.Add("column2", typeof(int));
table.Columns.Add("column3", typeof(string));
table.Rows.Add(1, 0, "a");
table.Rows.Add(2, 1, "b");
table.Rows.Add(3, 1, "c");
table.Rows.Add(4, 3, "d");
table.Rows.Add(5, 3, "e");
How can I do these using LINQ?
a. Return the DataRows whose values in column1 also appears in column2.
So far, I did this:
var x = (from t1 in table.AsEnumerable()
select t1.Field<int>(0)).Intersect
((from t2 in table.AsEnumerable()
select t2.Field<int>(1)).Distinct());
Bu the problem is, only the values of column1 is returned, which I use a foreach on. Probably because of the select t1.Field<int>(0) part, but I don't know how to return the DataRows itself.
b. Return the values of column3 whose values in column1 also appears in column2.
Almost the same question as [a]. I can only return the column1 row since I already used it. I don't know how to return the DataRows and other columns (e.g. column3) except column1.
I have also tried this:
var x1 = from t in table.AsEnumerable()
select t;
var x2 = (from t in table.AsEnumerable()
select t.Field<int>(1)).Distinct();
I was hoping to use Intersect() on x1 and x2, but I don't know how. Especially since x1 is kind of like a DataRow[] and x2 like an int[].
c. Using the answer in [a] for another query.
Or using something from a LINQ for another LINQ. i have no idea at all how to do something like this.
An approach:
a) var result = (from t1 in table.AsEnumerable()
join t2 in table.AsEnumerable() on t1.Field<int>(0) equals t2.Field<int>(1) select t1).Distinct();
The query above returnsIEnumerable<DataRow>.From this result you can select values of column3 like t2.Field<int>(2) for b) scenario.
I would create a new class for the three columns. Then create an Iqueryable or List for the new class and add the table rows into that. Then the Linq expression should work.
Class
public class myClass
{
public int column1
{
get;
set;
}
public int column2
{
get;
set;
}
public stringcolumn3
{
get;
set;
}
}
Linq
a. Return the DataRows whose values in column1 also appears in column2.
var x = (from l1 in myList
where (from l2 in myList
select l2.column2).contains(l1.column1)
select l1);
b. Return the values of column3 whose values in column1 also appears in column2.
var col3Values = (from l1 in myList
where l1.column2 = l1.column3
select l1.column3);
With help from guys here, and some other sites, I just found out how to actually do [b] above.
This returns the values in column3 whose values in column1 does not appear in column2:
from t in table.AsEnumerable()
join t2 in table.AsEnumerable().Select(i => i.Field<int>(0)).Except(table.AsEnumerable().Select(j => j.Field<int>(1)))
//the inner Select() returns column1 whose values in it also appears in column2
//I can use either this or the first LINQ I made above
//By the way, I said **does not** because I don't think I can use inner join on the opposite of [b]
//unlike the Select() with lambda above; I can just change the Intersect() to Except() :)
on t.Field<int>(0) equals t2
where t.Field<int>(1) > 2 //If I need some other condition
select t.Field<string>(2);
For [c], I made another table:
DataTable tableA = new DataTable();
tableA.Columns.Add("columnA", typeof(string));
tableA.Columns.Add("columnB", typeof(string));
tableA.Rows.Add("apple", "red");
tableA.Rows.Add("banana", "yellow");
tableA.Rows.Add("carrot", "orange");
tableA.Rows.Add("dog", "commonly brown"); //ok, I can't think of a fruit/vegetable that starts with 'd' right now...
tableA.Rows.Add("eggplant", "purple");
And renamed the first table to table1 to avoid/minimize confusion
var x = from tA in tableA.AsEnumerable()
from t1 in (
from t1 in table1.AsEnumerable()
join t2 in ((from t2_1 in table1.AsEnumerable()
select t2_1.Field<int>(0)).Except
((from t2_2 in table1.AsEnumerable()
select t2_2.Field<int>(1))).Distinct())
on t1.Field<int>(0) equals t2
where t1.Field<int>(1) > 2 //extra condition
select t1.Field<string>(2))
where tA.Field<string>(0).StartsWith(t1)
select tA;
This returns Rows in tableA whose columnA starts with the returned table1's column3, whose column1 values does not appear in column2 and has a value greater than 2 in its column2.

LINQ to SQL: How to implement a LEAST or similar function?

Given:
A table named TABLE_1 with the following columns:
ID
ColumnA
ColumnB
ColumnC
ColumnD
I have SQL query where TABLE_1 joins on itself twice based off of ColumnA, ColumnB, ColumnC. The query might look something like this:
Select t1.ID, t2.ID, t3.ID, LEAST(t1.ColumnD, t2.ColumnD, t3.ColumnD)
From TABLE_1 t1
Left Join TABLE_1 t2 On
t1.ColumnA = t2.ColumnA
And t1.ColumnB = t2.ColumnB
And t1.ColumnC = t2.ColumnC
Left Join TABLE_1 t3 On
t2.ColumnA = t3.ColumnA
And t2.ColumnB = t3.ColumnB
And t2.ColumnC = t3.ColumnC
Problem:
I need that Query to be rewritten in LINQ. I've tried taking a stab at it:
var query =
from t1 in myTABLE1List // List<TABLE_1>
join t2 in myTABLE1List
on new {t1.ColumnA, t1.ColumnB, t2.ColumnC}
equals new {t2.ColumnA, t2.ColumnB, t2.ColumnC}
join t3 in myTABLE1List
on new {t2.ColumnA, t2.ColumnB, t2.ColumnC}
equals new {t3.ColumnA, t3.ColumnB, t3.ColumnC}
select new {
ID_1 = s1.ID,
ID_2 = s2.ID,
ID_3 = s3.ID,
// Invalid anonymous type member declarator.
// Anonymous type members must be declared with a member assignment,
// simple name or member access.
// how can I implement this?
least(s1.ColumnD, s2.ColumnD, s3.ColumnD)
};
....
private object least(params object[] objects)
{
// code here that sorts the objects and returns the 'smallest' of them.
return leastObject;
}
How do I write my query in LINQ? What am I doing wrong? I thought it was possible to use functions inside of LINQ expressions, so why am I getting this error?
I could be wrong, but I think you need to assign the result of least to an actual member of your new anonymous type instance, e.g.:
select new {
ID_1 = s1.ID,
ID_2 = s2.ID,
ID_3 = s3.ID,
Least = least(s1.ColumnD, s2.ColumnD, s3.ColumnD)
};
How about?
MinOfColumnD = Math.Min(Math.Min(s1.ColumnD, s2.ColumnD), s3.ColumnD))
EDIT: Assuming that ColumnD in each of the table is numeric & 'least` (in this context) is minimum of 3 numbers in the given columns.
EDIT: If the columns are string, determine what max. values it can hold & do a .Parse on it.
For e.g.
MinOfColumnD = Math.Min(Math.Min(int.Parse(s1.ColumnD), int.Parse(s2.ColumnD)), int.Parse(s3.ColumnD)))

Categories