Linq to Entity Framework: Multiple left outer joins create full outer - c#

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
}
}

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{};

Joining 4 tables with left outer joins and inner join in LINQ

LINQPad Screenshot where TAanlysis is T2 table which I can expand to see details.
I have four tables. Three of them need to join with left while two of them with inner join.
Here is the SQL code that I'm trying to re-code within LINQ:
select t1.*,t2.*,t3.*
from t1
left outer join t2 on t1.column1=t2.column1
left outer join t3 on t2.column1=t3.column1
INNER join t4 on t2.column1=t4.column1
where t3.column2=x**
Can anyone help how to write such query in LINQ?
I tried below LINQ query in .NET which is yielding different SQL query at backend:
from prsn in db.T1
join co in db.T2 on prsn.Id equals co.Id into ps1
from y1 in ps1.DefaultIfEmpty()
join tproject in db.T3 on y1.Id equals prod.Id into ps2
from y2 in ps2.DefaultIfEmpty()
join res in db.T4 on y1.Id equals res.Id
where y2.ID == x
select prsn;[![enter image description here][1]][1]
SQL query formed at backend:
select filter1.*
from (Select t1.* from t1 inner join t2 on t1.Id=t2.Id
left outer join t3 on t2.Id = t3.Id)as filter1
inner join t4 on filter1.Id= t4.Id
where filter1.Id= x
I tried above LINQ query in .NET which is yielding different SQL query at the backend. Let me know if I am missing anything?
Note : selection of all columns from 3 tables.

Select In Select Statement

What is an equivalent LINQ query to the following SQL query:
Select Id, Name
From Table1 tbl1
Where Id in ( Select Id From Table2)
You basically described an inner join with selection of rows from one table:
var result = from t1 in Table1
join t2 in Table2
on t1.Id equals t2.Id
select new{t1.Id, t1.Name};
Next SQL statement will be generated using EF and MS SQL:
SELECT t1.Id, t1.Name
FROM Table1 AS t1
INNER JOIN Table2 AS t2 ON t1.Id = t2.Id
Note, that if you are selecting non-unique items from Table2, you can potentially have duplicates in the result. Use next query to avoid this problem, cons: it loads all ids from Table2 into memory, pros: more time efficient. Checkout Felipes answer's, which is also quite good, but has it's own cons discussed in the comment section.
var table2Ids = new HashSet<int>(context.Table2.Select(t2 => t2.Id));
var result = context.Table1
.Where(t => table2Ids.Contains(t.Id))
.Select(t => new{t.Id, t.Name});
try using the Contains method:
var query = from c in db.Table1
where db.Table2.Select(x => x.Id).Contains(c.Id)
select new { c.Id, c.Name };
var result = query.ToList();

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 };

LINQ2SQL - More Questions on when a Cross join with where clause is emitted instead of Inner Join

This is a two part question and for education purposes rather than trying to find a solution to a problem.
I've seen this already and realize that it's very similar to my question
LINQ2SQL - Cross join emitted when I want inner join
But I am hoping for more information from you LINQ and SQL gurus as to why the cross join is created instead of inner join in LINQ2SQL. Additionally, can someone explain how SQL Server decides on the execution plan (or link to further information) since both of these queries generate the same plan? From what I understand, this means that the performance of the queries are the same.
I've created a small example that runs two LINQ expressions on my database that generates these two different SQL queries.
For those who don't want to bother, here's my example db diagram:
http://dl.dropbox.com/u/13256/Screen%20shot%202011-03-16%20at%2011.41.56%20AM.png
Here are the two queries:
Cross Join with Where Clause
var q = from item in context.Items
join i_mem in context.Memberships on new { item_id = item.ID, user_id =
current_user_id.Value } equals new { item_id = i_mem.RelatedItemID, user_id =
i_mem.RelatedUserID } into sq_i_m
from im in sq_i_m.DefaultIfEmpty()
join i_cat in context.Categories on item.RelatedCategoryID equals i_cat.ID
into sq_i_cat
from proj in sq_i_cat
select item;
Inner Join
from item in context.Items
join i_mem in context.Memberships on
new { item_id = item.ID, user_id = current_user_id.Value }
equals
new { item_id = i_mem.RelatedItemID, user_id = i_mem.RelatedUserID }
into sq_i_m
from im in sq_i_m.DefaultIfEmpty()
join i_cat in context.Categories on item.RelatedCategoryID equals i_cat.ID
select item
And here is the test program if you'd like to see for yourself.
Thanks for everyone's help.
Mustafa
They are the same thing, so it does not matter which LINQ2SQL emits.
An inner join is logically equivalent to a cross join with a where clause filter equivalent to the on of the inner join clause.
That's why Sql Server generates the same query plan.
To be clear, the inner join:
Select f1
From T1 inner join T2 on T1.k = T2.k
where T1.f2 like 'X%'
Is the same as the cross join:
Select f1
From T1 cross join T2
where T1.k = T2.k
and T1.f2 like 'X%'
is the same as old-style SQL:
Select f1
From T1, T2
where T1.k = T2.k
and T1.f2 like 'X%'
Lets say you have a datacontext called MyDataContext.
using(MyDataContext db = new MyDataContext())
{
var q = db.Items.Where(x=> x.Categories.Name == "myCategory").Select(x=> x);
}
This is a very simple example, but you didn't need to write out a join or a subquery in TSQL syntax. (I hate writing TSQL).

Categories