简体   繁体   中英

lambda expression - equivalent of sql outer join

I need to write the method in C# that will return some specific dictionary from DB. Lets say that data stored in 2 tables looks like:

table Groups (id, name):

1, 'Management'  
2, 'IT Department'  
3, 'Production'  

The Users (id, name, groupId, projectId):

1, 'John', 1, 1  
2, 'Ben',  2, 1  

Now I need to check that in every project every group have no less than one user. The sql query to achieve this information will be:

declare @projectId int;  
set @projectId = 1;  

select g.Name, case when(isnull(u.id,0) > 0) then 1 else 0 end HasUsers  
from groups g  
left join users u  
on g.id = u.groupId and u.projectId = @projectId;  

The information that are returned from this query looks like bellow:

'Management',    1  
'IT Department', 1  
'Production',    0  

What's so special in the query? The condition for projectId is included in 'join' part, not 'where' part. In consequence the row for 'Production' group is returned with value 0. When we move condition for projectId to 'where part' the record will not be present in the return result.

Finally the question - is it possible to achieve similar effect using one lambda expression? (I know that I can achieve 2 collections and using some kind of loop statement get the final result, but it's not a subject of this question)

regards,
yaki

Ok, I think that I figured it out by myself. The sql produced is a little bit more complicated then provided in original post, but the resultset is the same.

var query = db
  .Groups
  .GroupJoin(db.Users.Where(u => u.projectId == 1) , g => g.Id, u => u.groupId, (g, u) => new { u, g })
  .SelectMany(x => x.u.DefaultIfEmpty(), (g,u) => new {Group = g.g, Users = u})
  .Select(res => new {Group = res.Group.Name, Counter = (res.Users != null)});

LINQ Outer Join queries take the form of this:

from x in collection
join y in otherCollection on x.Key equals y.Key into g
from o in g.DefaultIfEmpty()
select new Whatever {
    Something = x,
    Other = o
};

If there is no related y to join to the x , then the o selected from g will be null

Semi shot in the dark:

from g in groups 
join u in users on  
new { a = g.id, b=u.projectid } equals new { a = u.groupid, b = [var_goes_here] } into t 
from u in ps.DefaultIfEmpty() 
select new { GroupName = g.name, HasUsers = u == null ? 0 : 1 };

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM