How to get an outerjoin on a Linq query - linq

Given this linq query
from c in context.Customers
from o in c.Orders
where c.City == "MyCity" || o.ShipTo == "MyCity"
select c
the query will not return any rows if the customer's city is "MyCity" but does not have any orders. This is because of the implied inner join between Customers and Orders. How do I select customers with a City of "MyCity" or order shipped to "MyCity
In this case I need an outer join between Customers and Orders. How do I express that in Linq? I think the approximate TSQL would be
select customers.*
from customers
left join orders on customers.id = orders.customerid
where customers.city = 'MyCity' or orders.ShipTo = 'MyCity'

To get an outer join, you can use DefaultIfEmpty. See this question: Linq to Sql: Multiple left outer joins
from c in context.Customers
from o in context.Orders
.Where(a => a.customerid == c.id)
.DefaultIfEmpty()
where c.City == "MyCity" || o.ShipTo == "MyCity"
select c
Alternatively, you can do this:
from c in context.Customers
join o in context.Orders on c.id equals o.customerid into g
from x in g.DefaultIfEmpty()
where c.City == "MyCity" || x.ShipTo == "MyCity"
select c
I believe they both generate the same SQL.

You have to use DefaultIfEmpty
I think something like this would work
var result = from c in context.Customers
join o in c.Orders on c.CustomerId equals o.CustomerId into lj
from or in lj.DefaultIfEmpty()
where c.City == "MyCity" || or.ShipTo == "MyCity"
select c

Related

cast to value type 'System.Int32' failed because the materialized value is null

I have a Linq Query but it gives above error I guess due to NULL as I have Module,Block and semester as nullable int when semester column is having value than Module and Block would be null and when Module and block would be null than semster is having value How to handle the below query.
var test1 = (from c in db.StudentCoursesAssigned
join e in db.Years
on c.Year_Id equals e.Id into table1 from e in table1.DefaultIfEmpty()
join cc in db.Courses
on c.Course_Id equals cc.Course_Id into table2 from cc in table2.DefaultIfEmpty()
join g in db.grades
on c.Grade equals g.Id into table3 from g in table3.DefaultIfEmpty()
join m in db.Moduels
on c.Module_Id equals m.Id into table4 from m in table4.DefaultIfEmpty()
join p in db.Programs
on c.Program_Id equals p.Id into table5 from p in table5.DefaultIfEmpty()
join b in db.Blocks
on c.Block_Id equals b.Id into table6 from b in table6.DefaultIfEmpty()
join s in db.Semesters
on c.Semster_Id equals s.Semester_Id into table7 from s in table7.DefaultIfEmpty()
join ss in db.Students
on c.Student_id equals ss.Student_Id into table8 from ss in table8.DefaultIfEmpty()
select new
{
Student_Name=ss.Student_FName,
Course=cc.Course_Name,
Active=c.Active,
Course_start_date=c.Enrolment_Start,
Course_End_date=c.Enrolment_End,
Grade=g.Name,
Module=m.Name,
Program=p.Program_Title,
Year=e.Id,
Semester=s.Semester_Title,
blocks=b.Id
}).ToList();
That is the right Linq query which solves
var test1 = (from c in db.StudentCoursesAssigned
join e in db.Years
on c.Year_Id equals e.Id into table1 from e in table1.DefaultIfEmpty()
join cc in db.Courses
on c.Course_Id equals cc.Course_Id into table2 from cc in table2.DefaultIfEmpty()
join g in db.grades
on c.Grade equals g.Id into table3 from g in table3.DefaultIfEmpty()
join m in db.Moduels
on c.Module_Id equals m.Id into table4 from m in table4.DefaultIfEmpty()
join p in db.Programs
on c.Program_Id equals p.Id into table5 from p in table5.DefaultIfEmpty()
join b in db.Blocks
on c.Block_Id equals b.Id into table6 from b in table6.DefaultIfEmpty()
join s in db.Semesters
on c.Semster_Id equals s.Semester_Id into table7 from s in table7.DefaultIfEmpty()
join ss in db.Students
on c.Student_id equals ss.Student_Id into table8 from ss in table8.DefaultIfEmpty()
select new
{
Student_Name = ss.Student_FName == null ? "No Value" : ss.Student_FName,
Course = cc.Course_Name == null ? "No Value" : cc.Course_Name,
Active = c.Active ,
Course_start_date = c.Enrolment_Start,
Course_End_date = c.Enrolment_End ,
Grade = g.Name == null ? "No Value" : g.Name,
Module = m.Name == null ? "No value" : m.Name,
Program=p.Program_Title == null ? "No Value" : p.Program_Title,
Year=e.Name,
Semester=s.Semester_Title == null ? "No Value" : s.Semester_Title,
blocks=b.Name == null ? "No Value":b.Name,
student_Id=ss.Student_Id,
id=c.Id,
}).ToList();
```

Why my Linq query gives wrong results

I have this SQL query which gives the output as 15.but, when I converted the same query in Linq,it gives an output as 72.
select sum(DATEDIFF(day,LeaveBreakup.StartDate,LeaveBreakup.EndDate)+1) as totalNoOfDays from LeaveApplication
inner join Employee
on LeaveApplication.Employee=Employee.Id
inner join Team
on Employee.Team=Team.Id
inner join LeaveBreakup
on LeaveApplication.Id=LeaveBreakup.LeaveApplication
inner join LeaveTypeDetail
on LeaveBreakup.LeaveType=LeaveTypeDetail.LeaveType
where Employee.Team=5 and LeaveStatus!=0 and LeaveBreakup.StartDate between '01-01-2016' and '01-31-2016' and LeaveBreakup.WhichHalf=0
var Stafflist = (from LApp in db.LeaveApplications
join Emp in db.Employees
on LApp.Employee equals Emp.Id
join Tm in db.Teams
on Emp.Team equals Tm.Id
join LBrk in db.LeaveBreakups
on LApp.Id equals LBrk.LeaveApplication
join LTD in db.LeaveTypeDetails
on LBrk.LeaveType equals LTD.LeaveType
where Emp.Team == 5 && LApp.LeaveStatus != 0 && LBrk.StartDate >= d1 && LBrk.StartDate <= d2 && LBrk.WhichHalf == 0
select DbFunctions.DiffMinutes(LBrk.StartDate, LBrk.EndDate)).Sum() / 60;

Linq left outer join and group by issue

Hi All my following query returns results like this:
lstView.DataSource = (from h in context.HolidayMains
join hd in context.HolidayDetails on h.Id equals hd.HolidayMainId into hd2
from hd in hd2.DefaultIfEmpty()
join e in context.Employees on h.CreatedBy equals e.Id into e2
from e in e2.DefaultIfEmpty()
join o in context.OfficeLocations on hd.OfficeLocation equals o.Id into o2
from o in o2.DefaultIfEmpty()
select new
{
h.HolidayTitle,
h.Date,
OfficeLocation = o.Name,
CreatedBy = e.Name,
h.Id
}).ToList();
But I need result like this :
How it can be done?

join on subquery results

I've got a table called IssueStatuses and another table called Issues. Issues has a StatusID and SubStatusID, both of which are from the IssueStatuses table which has an additional field that states if it's a SubStatus or not, like so:
IssueStatuses
IssueStatusID
IssueStatus
IsSubStatus
I'm trying to get a list of SubStatuses for a particular list of Issues. In SQL it's:
SELECT iss.IssueStatus, COUNT(iss.IssueStatus) AS Total
FROM Issues AS Issues
INNER JOIN Rooms r ON Issues.RoomID = r.RoomID
INNER JOIN Locations l ON l.LocationID = r.LocationID
INNER JOIN Customers c ON l.CustomerID = c.CustomerID
INNER JOIN (SELECT * FROM IssueStatuses WHERE IsSubStatus = 0) ist ON Issues.IssueStatusID = ist.IssueStatusID
INNER JOIN (SELECT * FROM IssueStatuses WHERE IsSubStatus = 1) iss ON Issues.IssueSubStatusID = iss.IssueStatusID
WHERE c.Customer = 'ABC'
AND l.Location = 'MySite'
GROUP BY iss.IssueStatus
but I"m having trouble converting it to LINQ. The desired output would be something like:
IssueStatus | Total
-------------------
Open 15
Delayed 25
On Time 8
Here's what I've tried with LINQ:
var query = from i in Issues
join r in Rooms on i.RoomID equals r.RoomID
join l in Locations on r.RoomID equals l.LocationID
join c in Customers on l.CustomerID equals c.CustomerID
where i.IssueStatusID == (from ist in IssueStatuses
where ist.IsSubStatus == false
select ist)
&& i.IssueSubStatusID == (from iss in IssueStatuses
where iss.IsSubStatus == true
select iss)
&& c.Custome == "ABC"
&& l.Location == "MySite"
group i by i.IssueStatus
but I know it's wrong because LINQPad throws an error stating:
can't convert int to type Models.IssueStatus
What I need to do is use iss.IssueStaus to group on but I can't access it. Can someone tell me what I'm doing wrong?
How about this (untested but I should be close):
var query = from i in Issues
join r in Rooms on i.RoomID equals r.RoomID
join l in Locations on r.LocationID equals l.LocationID
join c in Customers on l.CustomerID equals c.CustomerID
join ist in IssueStatuses on i.IssueStatusID equals ist.IssueStatusID
join iss in IssueStatuses on i.IssueSubStatusID equals iss.IssueStatusID
where !ist.IsSubStatus && iss.IsSubStatus
&& c.Customer == "ABC"
&& l.Location == "MySite"
group i by iss.IssueStatus into g
select new {IssueStatus = g.Key, Total = g.Count()}
Your two inner from statements return objects and not IDs ... select the ID you need like ist.IssueStatusID:
var query = from i in Issues
join r in Rooms on i.RoomID equals r.RoomID
join l in Locations on r.RoomID equals l.LocationID
join c in Customers on l.CustomerID equals c.CustomerID
where (from ist in IssueStatuses
where ist.IsSubStatus == false
select ist.IssueStatusID).Contains(i.IssusStatusID)
&& (from iss in IssueStatuses
where iss.IsSubStatus == true
select iss.IssueStatusID).Contains(i.IssueSubStatusID)
&& c.Customer == "ABC"
&& l.Location == "MySite"
group i by i.IssueStatus

left outer join problem

I need to convert some SQL statement to LINQ. How convert LEFT OUTER JOIN to equivalent LINQ statement?
You need to use the DefaultIfEmpty operator. The below code should result in a left outer join.
var q = from c in customers
join o in orders on c.Key equals o.Key into g
from o in g.DefaultIfEmpty()
select new {Name = c.Name, OrderNumber = o == null ? "(no orders)" : o.OrderNumber};
Credit to: http://www.hookedonlinq.com/OuterJoinSample.ashx

Resources