Multiple joins and logical operators - c#

I would need some guidance to convert this query in LINQ (method-based or expression syntax):
SELECT * from table1 t1
JOIN table2 t2 ON t1.fieldA = t2.fieldA and t1.fieldB = t2.fieldB
JOIN table3 t3 ON t2.fieldC = t3.fieldA
WHERE
t3.Enabled=1 and
t2.Active = 1 and
t1.Linked=1;
Using expression syntax it seems logical operators are not supported in the join clause.
My failed attempt:
var query = from t1 in context.table1
join t2 in context.table2 on t1.fieldA equals t2.fieldB && t1.fieldB equals t2.fieldB
join t3 in context.table3 on t3.fieldA equals t3.fieldC
where
t1.Enabled == 1 && t2.Active == 1 && t3.Linked == 1;

EF does not support multiple objects to be used for joining, instead, you can create object that will contain all properties you want to apply equals on:
var query = from t1 in context.table1
join t2 in context.table2 on new {t1.fieldA, t1.fieldB} equals new {t2.fieldA, t2.fieldB}
join t3 in context.table3 on t3.fieldA equals t3.fieldC
where
t1.Enabled == 1 && t2.Active == 1 && t3.Linked == 1 ...

you code has wrong third condition
instead of
join t3 in context.table3 on t3.fieldA equals t3.fieldC
put
join t3 in context.table3 on t2.fieldC equals t3.fieldA

Related

How to apply Right Outer Join using LINQ in C#?

I am facing issue to apply Right Outer Join in LINQ. I am trying to build the similar query in LINQ by converting from SQL query.
My correct SQL query
select *
from Table1 t1
inner join Table2 t2 on t1.Id = t2.FID and t1.CID = 20
right outer join Table3 t3 on t1.GID = t3.GID
var result = from t1 in Table1
join t2 in Table2
on t1.ID equals t2.FID into gr1
where t1.CID = 20
join t3 in Table3
on t1.GID equals t3.GID into gr2
from t3 in gr2.DefaultIfEmpty()
select new Details (){
}
return result.ToList();
}
My LINQ query is not working as expected to SQL query.
This is also discussed here
how to make a right join using LINQ to SQL & C#
var RightJoin = from adds in dc.EmpresaAddendas
join cats in CatAddendas
on adds.IDAddenda equals cats.IDAddenda into joined
from cats in joined.DefaultIfEmpty()
select new
{
Id = cats.IDAddenda,
Description = cats.Descripcion
};
Try this:
var result = from t1 in Table1
join t2 in Table2
on new { id = t1.ID; cid = t1.CID } equals new { id = t2.FID: cid = 20} into gr1
join t3 in Table3
on t1.GID equals t3.GID into gr2
from t123 in gr2.DefaultIfEmpty()
select new Details (){
}
return result.ToList();
}
As you're discovered, most LINQ providers don't offer support for a right join. DefaultIfEmpty translates into a LEFT join. As a result, you need to flip the logic of your query around a bit to turn the right join into a left one.
As far as the actual syntax, I've had success adopting more of an ANSI-82 syntax rather than worrying about the into temp2 from temp3 in temp2 syntax. Something along the lines of:
var result =
from t3 in Table3
from t1 in Table1.Where(temp1 => temp1.GID == t3.GID).DefaultIfEmpty()
join t2 in Table2 on t1ID equals t2.FID
where t1.CID == 20
select new Details{};

Issues in converting SQL to LINQ

I have a sql query like below (table and column names are arbitrary for the sake of question):
select t3.MRIID as 'Ids'
from table1 t1
join table2 t2 with (nolock) on t1.ID = t2.SPID
join table3 t3 with (nolock) on t2.ID = t3.SPMRID
join table4 t4 on t4.MRID = t3.MRID
where
t3.MRISID = 18
and t1.ID = 315
group by t3.MRIID
having SUM(CAST(t4.IRGPC AS INT)) > 0
I am trying to convert this to an equivalent LINQ query and this is what I have so far. This does not give me the intended result when I run it in LINQPad and was wondering if anyone has explanation to where I am going wrong? I know my group/having clauses are the issues here but not sure how to solve it.
from t1 in table1
join t2 in table2 on t1.ID equals t2.SPID
join t3 in table3 on t2.ID equals t3.SPMRID
join t4 in table4 on t3.MRID equals t4.ID
where t3.MRISID == 18 && t1.ID == 315
group new { t1, t2, t3, t4 } by t3.MRID into groupedResult
let count = groupedResult.Count()
where count > 0
select new { Something = groupedResult.Key}
The SQL query gives me 2 'Ids' in result which is expected as compared to Linq query giving me 3 out of which 1 'Id' does not match the having clause
Help greatly appreciated!
[UPDATE] I just noticed my having clause in sql query is not what is there in Linq equivalent and am trying to understand how to accomplish that?
Based on Mrinal's solution (and chat comments), My LINQ now stands at
from t1 in table1
join t2 in table2 on t1.ID equals t2.SPID
join t3 in table3 on t2.ID equals t3.SPMRID
join t4 in table4 on t3.MRID equals t4.ID
where t3.MRISID == 18 && t1.ID == 315
group Convert.ToInt32(cd.IRGPC) by mriw.MRIID into groupedResult
where groupedResult.Sum() > 0
select new { groupedResult.Key}
However, this is still not matching the results of what the original SQL statement gives. I Ran this linq query through LinqPad to see the generated SQL and it looks like below.
-- Region Parameters
DECLARE #p0 Int = 18
DECLARE #p1 Int = 315
DECLARE #p2 Int = 0
-- EndRegion
SELECT [t5].[MRIID] AS [Key]
FROM (
SELECT SUM([t4].[value]) AS [value], [t4].[MRIID]
FROM (
SELECT CONVERT(Int,[t3].[IRGPC]) AS [value], [t2].[MRISID], [t0].[ID], [t2].[MRIID]
FROM [table1] AS [t0]
INNER JOIN [table2] AS [t1] ON [t0].[ID] = [t1].[SPID]
INNER JOIN [table3] AS [t2] ON [t1].[ID] = [t2].[SPMRID]
INNER JOIN [table4] AS [t3] ON [t2].[MRIID] = [t3].[ID]
) AS [t4]
WHERE ([t4].[MRISID] = #p0) AND ([t4].[ID] = #p1)
GROUP BY [t4].[MRIID]
) AS [t5]
WHERE [t5].[value] > #p2
If this extra bit of detail helps, the IRGPC column is a bit type in SQL and bool type in C# code.
Any suggestions?
Try modifying the Linq query as follows:
from t1 in table1
join t2 in table2 on t1.ID equals t2.SPID
join t3 in table3 on t2.ID equals t3.SPMRID
join t4 in table4 on t3.MRID equals t4.ID
where t3.MRISID == 18 && t1.ID == 315
group new { t1, t2, t3, t4 } by t3.MRID into groupedResult
where groupedResult.Sum(y => (int)y.t4.IRGPC) > 0
select new { Something = groupedResult.Key }
Modification:
Changed the groupedResult.Count() > 0 to groupedResult.Sum(y => (int)y.t4.IRGPC) > 0, since in the Sql query you have having SUM(CAST(t4.IRGPC AS INT)) > 0, which needs to replicated in the Linq Query
EDIT 1:
As mentioned by OP, t4.IRGPC is a boolean type and use case is to get one grouping, which has at least one value true, try the following option:
group t4.IRGPC by t3.MRID into groupedResult
where groupedResult.Any(x => x)
Instead of
let count = groupedResult.Count()
where count > 0
use where clause
where groupedResult.Sum(x => x.t4.IRGPC) > 0

SQL to LINQ - Left Join two conditions

How can I convert this outer left join to LINQ?
SELECT * from table1 t1
left join table2 t2 on t1.code = t2.code AND t2.id ='xxxxx'
WHERE t1.someId = 2
I'm trying something like this:
from t1 in db.table1
join t2 in db.table2 on t1.Code equals t2.Code
into oj
from sub in oj.DefaultIfEmpty()
where t1.someId == 2
where (sub.id == 'xxxx')
but not all rows from left table are being returned. The where clauses i think are applied after the join.
var res=(from t1 in table1.Where(x=>x.someId==2)
join t2 in table2.Where(y=>y.id==xxxx)
on t1.code = t2.code
into r
from t3 in r.DefaultIfEmpty()
select new {t1,t3}).ToList();

c# I need to perform this SQL Select to LINQ

I have this Select:
SELECT (MyFields)
FROM table1 T1
INNER JOIN table2 t2 ON t2.ID_t2 = T1.ID_T1
INNER JOIN
table3 t3 on t3.ID_t3=T1.ID_T1 and Left(t3.Other_t3_field,5)=t2.Another_t2_field
WHERE (Conditions)
Then, I tried in C#:
var query = from T1 in table1
join t2 in table2 on T1.ID_T1 equals t2.ID_t2
join t3 in **table3** on T1.ID_T1 equals v.ID_t3
join t4 in **table3** on t2.Other_t2_field equals Microsoft.VisualBasic.Strings.Left(t2.Another_t3_field, 5)
where (Conditions)
select new
{
(My fields)
};
Both works, but my C# query have more results then SQL Select, I don't know what I am doing wrong?
Well I'd start by changing the join on table 3 in the C# - use an anonymous type to join on multiple fields:
join t3 in table3 on new { Id = t1.ID_T1, X = t2.AnotherT2Field.Substring(0, 5) }
equals new { Id = t3.ID_T3, X = t3.OtherT3Field.Substring(0, 5) }
(I'd hope you can use Substring instead of Left here... it's much more idiomatic C#.)
You can add multiple join conditions with an anonymous type:
var query = from T1 in table1
join t2 in table2 on T1.ID_T1 equals t2.ID_t2
join t3 in **table3** on new {
ID = T1.ID_T1,
substring = t2.Other_t2_field
} equals new
{
ID = v.ID_t3,
substring = Microsoft.VisualBasic.Strings.Left(t2.Another_t3_field, 5)
}
where (Conditions)
select new
{
(My fields)
};
As Jon Skeet mentioned: you can also use Substring instead of Left.

LINQ multiple joins with multiple conditions

I have few large tables and I need to join them. In SQL it looks like:
select * from dbo.Table1 t1
join dbo.Table1 t1Parent on t1.ParentId = t1Parent.Id
join dbo.MappingT1T3 t2 on t1Parent.Id = t2.ExternalId and t2.[Type] = 1
join dbo.Table3 t3 on t2.ForeignId = t3 .Id
where t1.[Type] = 3
Tried to convert this query to a such LINQ:
from t1 in dbo.Table1
join t1Parent in dbo.Table1 on t1.ParentId equals t1Parent.Id
join t2 in dbo.MappingT1T3 on new { Id = t1Parent.Id, [Type] = (int)1 } equals new { Id = t2.ExternalId, [Type] = (int)t2.[Type] }
join t3 in dbo.Table3 on t2.ForeignId equals t3.Id
where t1.[Type] == 3;
But seems execution plan differs a lot. Profile says that it tries to load all tables without conditions..
Try putting the constant to a seperate condition...
from t1 in dbo.Table1
where t1.[Type] == 3 // <--- PUT THIS ONE HIGHER
join t1Parent in dbo.Table1 on t1.ParentId equals t1Parent.Id
join t2 in dbo.MappingT1T3 on t1Parent.Id equals Id = t2.ExternalId
where (int)t2.[Type] == 1 // <--- SEPARATE CONDITION
join t3 in dbo.Table3 on t2.ForeignId equals t3.Id;

Categories