Multiple on clause in LINQ to DataTable Join Query - c#

So I have two DataTables that have the same schema, but different data. I want to join the two tables together where two fields, id3 and print and the same. How would I write this in LINQ?
Right now, this works and gives no compiler errors:
var singOneJoin =
from prod in singOneProd.Table.AsEnumerable()
join agg in singOneAgg.Table.AsEnumerable()
on prod.Field<string>("print") equals agg.Field<string>("print")
select new
{
print = prod.Field<string>("print")
};
But what I really want is this:
var singOneJoin =
from prod in singOneProd.Table.AsEnumerable()
join agg in singOneAgg.Table.AsEnumerable()
on (prod.Field<string>("print") equals agg.Field<string>("print") &&
prod.Field<Int32>("id3") equals agg.Field<Int32><("id3"))
select new
{
print = prod.Field<string>("print")
};
But this gives me compiler errors.
How do I join these two tables together on both the print and the id3 columns?
Regards,
Kyle

Use anonymous objects to join on multiple fields:
var singOneJoin =
from prod in singOneProd.Table.AsEnumerable()
join agg in singOneAgg.Table.AsEnumerable()
on new {
Print = prod.Field<string>("print"),
Id3 = prod.Field<Int32>("id3")
} equals new {
Print = agg.Field<string>("print"),
Id3 = agg.Field<Int32>("id3")
}
select new {
print = prod.Field<string>("print")
};
Keep in mind that anonymous object property names should match.

Related

Linq query to get get count from multiple tables

I have a query wherein I need to get the count from 2 different tables. Here is a very simple form of the query (my query has more joins and conditions but this is the part I am stuck on):
select (select count(1) from Table1) as One, (select count(1) from Table2) as Two
The following linq queries works but I would like to do the above with a single linq query sent to the SQL Server. This query and many other versions I have tried, result in 2 queries sent to the server:
var query1 = from m in this.Table1 select m;
var query2 = from sr in this.Table2 select sr;
var final = new { One = query1.Count(), Two = query2.Count() };
I also tried this and this also sends 2 queries:
var final = from dummy in new List<int> { 1 }
join one in query1 on 1 equals 1 into ones
join two in query2 on 1 equals 1 into twos
select new { One = ones.Count(), Two = twos.Count()};
You need to make it a single LINQ query that can be translated:
var final = (from m in this.Table1.DefaultIfEmpty()
select new {
One = (from m in this.Table1 select m).Count(),
Two = (from sr in this.Table2 select sr).Count()
}).First();
Note that putting the sub-queries into an IQueryable variable will cause three separate queries to be sent.
Alternatively, since Count() doesn't have a query syntax equivalent, this is a little more compact in lambda syntax:
var final = this.Table1.DefaultIfEmpty().Select(t => new {
One = this.Table1.Count(),
Two = this.Table2.Count()
}).First();

Cannot make 5 consecutive "joins" in LINQ?

I have this rather complex query in SQL server 2008:
declare #LanguageID as int = 1
select k.datePublish, k.dateEditing, k.dateTables
from TableAreasLevel1 as areaL1
inner join TableAreasLevel2 as areaL2
on areaL1.LanguageID = areaL2.LanguageID and
areaL1.CodeAreaLevel1 = areaL2.CodeAreaLevel1
inner join TableAreasLink as link
on areaL2.CodeAreaLevel1 = link.CodeAreaLevel1 and
areaL2.CodeAreaLevel2 = link.CodeAreaLevel2 and
inner join TableProducts as tblProds
on tblProds.CodeAreaLevel1 = areaL1.CodeAreaLevel1 and
tblProds.CodeAreaLevel2 = areaL2.CodeAreaLevel2
inner join TableSI_Products as prod
on prod.SiAreaCode = link.SiAreaCode
inner join TableCalendar as k
on k.KodTableSI_Products = tblProds.KodTableSI_Products
where areaL1.LanguageID = #LanguageID and
prod.Code = 'some string' and
k.LanguageID = #LanguageID and
tblProds.LanguageID = #LanguageID;
I am trying to develop the same query in LINQ, but I get error when I try join the table TableProducts, i.e the third consecutive join.
Here is my LINQ query:
List<Tuple<DateTime, DateTime, DateTime>> dates = (from areaL1 in gpe.TableAreasLevel1
join areaL2 in gpe.TableAreasLevel2
on new { areaL1.CodeAreaLevel1, areaL1.LanguageID } equals
new { areaL2.CodeAreaLevel1, areaL2.LanguageID }
join link in gpe.TableAreasLink
on new { areaL2.CodeAreaLevel1, areaL2.CodeAreaLevel2, areaL2.RbrOblastNivo2} equals
new {link.CodeAreaLevel1, link.CodeAreaLevel2}
join tblProds in gpe.TableProducts
on tblProds. // The name tblProds is not in the scope of the left side of 'equals'
);
Is the problem connected with how the tables are designed or, something else I should check for?
Any ideas, why tblProds is not visible in the scope of the LINQ query?
You are using Query as your guide something like:
on k.KodTableSI_Products = tblProds.KodTableSI_Products
but take a look at your linq:
on new { areaL1.CodeAreaLevel1, areaL1.LanguageID } equals
it has two fields. I think its not a good idea.
linq join something like
var dates = (from areaL1 in gpe.TableAreasLevel1
join areaL2 in gpe.TableAreasLevel2
on areaL1.PKFields equals areaL2.PKFields
where areaL1.CodeAreaLevel1== areaL2.CodeAreaLevel1 && areaL1.LanguageID = areaL2.LanguageID
Select new YournewClass{YournewClass.Field1=areaL1.fields1, And so on}
)
You can do to join the other tables with aliases.
Sorry need to go for now.
I'm giving you an idea.
Hope it helps.

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?

Convert SQL with multiple joins (with multiple conditions) of the same table to LINQ

How to convert an SQL to LINQ? Basically, I have a project_mstr table that has a PR_CLASS, PR_TYP and PR_GRP columns. Those 3 columns are values in the params_mstr under param_cd. For example, there's a record that has a PR_TYP value in param_cd with a Regular as its corresponding param_val value.
I installed Linquer but I'm not comfortable using it since I still have to create a connection to my database. I can't also find an online SQL to LINQ converter. So I'm asking the good guys here to please help me with the conversion.
SELECT
c.pr_id, c.pr_class, c.pr_typ, c.pr_grp, cp.pr_price,
c.gl_acct_id, c.pr_DESC "Project",
pm.param_val "Project Class", pm2.param_val "Project Type", pm3.param_val "Project Group"
FROM project_mstr c
JOIN
params_mstr pm ON c.pr_class = pm.param_id AND pm.param_cd = 'PR_CLASS'
JOIN
params_mstr pm2 ON c.pr_typ = pm2.param_id AND pm2.param_cd = 'PR_TYP'
JOIN
params_mstr pm3 ON c.pr_grp = pm3.param_id AND pm3.param_cd = 'PR_GRP'
JOIN
pr_price_mstr cp ON c.pr_id = cp.pr_id
JOIN
gl_acct_mstr gl ON c.gl_acct_id = gl.gl_acct_id
ORDER BY
c.crea_dt DESC;
LINQ-to-SQL only support equijoins, so if you need to introduce multiple values into the join, you can create an anonymous class to represent all of the values being joined on (note that the anonymous classes need to be the same type, which means that they need to have (1) exactly the same names of fields (2) of exactly the same type (3) in exactly the same order).
from c in ProjectMstr
join pm in ParamsMstr on new { ParamId = c.ChClass, ParamCd = "CH_CLASS" } equals new { pm.ParamId, pm.ParamCd }
join pm2 in ParamsMstr on new { ParamId = c.ChClass, ParamCd = "CH_TYP" } equals new { pm2.ParamId, pm2.ParamCd }
join pm3 in ParamsMstr on new { ParamId = c.ChClass, ParamCd = "CH_GRP" } equals new { pm3.ParamId, pm3.ParamCd }
// …
orderby c.CreaDt descending
select new {
c.ChId,
// …
ProjectClass = pm.ParamVal,
ProjectType = pm2.ParamVal,
ProjectGroup = pm3.ParamVal,
}
Alternatively, if it doesn't change the logic of the query, you can pull out the constant value from the join into a where.
from c in ProjectMstr
join pm in ParamsMstr on c.ChClass equals pm.ParamId
join pm2 in ParamsMstr on c.ChClass equals pm2.ParamId
join pm3 in ParamsMstr on c.ChClass equals pm3.ParamId
// …
where pm.ParamCd == "CH_CLASS"
where pm2.ParamCd == "CH_TYP"
where pm3.ParamCd == "CH_GRP"
orderby c.CreaDt descending
select new {
c.ChId,
// …
ProjectClass = pm.ParamVal,
ProjectType = pm2.ParamVal,
ProjectGroup = pm3.ParamVal,
}

Comparing two datatables through Linq

Hi I'm trying to compare two datatable through Linq. But I get this exception:
Specific cast is invalid
Please help me as I am new to Linq. This is the code I'm using:
var matched1 = from table1 in dtAvailableStores.AsEnumerable()
join table2 in dtControlStores.AsEnumerable()
on table1.Field<int>("STORE_NBR")
equals table2.Field<int>("STORE_NBR")
select table1;
Here STORE_NBR is a string value.
You can have a fairly good idea with this piece of code:
var qry1 = datatable1.AsEnumerable().Select(a => new { MobileNo = a["ID"].ToString() });
var qry2 = datatable2.AsEnumerable().Select(b => new { MobileNo = b["ID"].ToString() });
var exceptAB = qry1.Except(qry2);
DataTable dtMisMatch = (from a in datatable1.AsEnumerable() join ab in exceptAB on a["ID"].ToString() equals ab.MobileNo select a).CopyToDataTable();
References:
Compare two datatable using LINQ Query
Compare two DataTables for differences in C#?
This would happen if that field isn't actually an int.

Categories