How to apply Right Outer Join using LINQ in C#? - 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{};

Related

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;

Linq to Entity Framework: Multiple left outer joins create full outer

I can't find a good example, probably I'm searching wrong:
I have a bunch of tables joined via expression syntax and I'd like to left outer join two more, if there are values, otherwise return NULL.
So the sql is looking like this:
select *
from table1 mr
left outer join table2 on table1
left outer join table3 on table2
left outer join table4 on table3
where mr.id = 1234
So a left join is no problem with the syntax like this:
join oiA in query1 on organisation.Id equals oiA.Organisationid into qOrgInhA
from oiA in qOrgInhA.DefaultIfEmpty()
But as soon as I add the other tables depending on the oiA, the Entity Framework produces a Cross-Join, and not a second left outer join.
From what I've read, GroupJoin might be the solution, but I really can't find a good example, the most examples I found have just 2 tables.
Or am I doing something totally wrong?
In method syntax, multiple left joins can be done like this:
var result = table1
.GroupJoin(table2, o => o.Key, i => i.FKey, (t1, t2) => new
{
t1,
t2.GroupJoin(table3, o => o.Key, i => i.FKey, (_t2, t3) => new
{
_t2,
t3
})
});
The resulting query produced by entity framework will be similar to:
select * from table1
left outer join table2 on table1.Key = table2.FKey
left outer join table3 on table2.Key = table3.FKey
Edit:
I'm a bit shaky on query syntax, but its the same idea of doing the second join within the select:
var result = from t1 in table1
join t2 in table2 on t1.Key equals t2.FKey into joinresult
select new
{
t1,
from jr in joinresult
join t3 in table3 on jr.Key eq t3.FKey into joinresult2
select new
{
jr,
joinresult2
}
}

Convert regular SQL to LINQ to Entities

After a lot of search, I cannot find a simple answer to this following SQL Statement :
SELECT t1.LoginName, t0.BNAME
FROM USR02 AS t0
LEFT OUTER JOIN LoginData AS t1
INNER JOIN Mandants AS t2 ON t1.Id_Mandants = t2.Id_Mandants
ON t0.BNAME = t1.LoginName AND t0.MANDT = t2.CodeMandant
Because of the double ON statement I don't know how to write it in LINQ.
I've tried to simplify it but multiple primary key make the job hard.
Start by translating the SQL query to one that is more natural. Like this:
SELECT t1.LoginName, t0.BNAME
FROM USR02 AS t0
LEFT OUTER JOIN LoginData AS t1
ON t0.BNAME = t1.LoginName
INNER JOIN Mandants AS t2
ON t1.Id_Mandants = t2.Id_Mandants
WHERE t0.MANDT = t2.CodeMandant
Now it should be easy to translate this to LINQ. When you have you have set up the relationships in your entity model correctly, you would be able to write the following LINQ query:
from data in db.LoginData
where data.User.MANDT == data.Mandant.CodeMandant
select new { data.LoginName, data.User.BNAME };
btw. Why are you outputting both LoginData.LoginName as USR02.BNAME since they are always equal?
You need to convert your query to regular, 1-level join:
select t1.LoginName, t0.BNAME
from USR02 as t0
left outer join LoginData as t1 on t0.BNAME = t1.LoginName
inner join Mandants as t2 on t0.MANDT = t2.CodeMandant and t1.Id_Mandants = t2.Id_Mandants
Then it will be much easier to rewrite it on LINQ to Entities:
from t0 in db.t0
join t1 in db.t1 on t0.BNAME equals t1.LoginName
join t2 in db.t2 on new { t0.MANDT, t1.Id_Mandants} equals new { t2.CodeMandant , t2.Id_Mandants }
select new { t1.LoginName, t0.BNAME };
I like writing joins in this way
from t0 in db.t0
from t1 in db.t1.Where(x => t0.BNAME == x.LoginName).DefaultIfEmpty()
from t2 in db.t2.Where(x => t0.MANDT == x.CodeMandant)
.Where(x => t1.Id_Mandants == x.Mandants)
select new { t1.LoginName, t0.BNAME };

Categories