I've been using Linq to SQL and have started using Entity Framework for a new project. I use LinqPad to test my code before incorporating it into Visual Studio. While debugging in VS, I noticed my counts differed. When I inspected the SQL created by my code in VS, I noticed that it didn't translate correctly.
My code in VS:
var adviceLineCallTotalViewModelList =
from a in db.AdviceLineCalls
.Include(a => a.Agency)
.Include(a => a.Staff)
.Include(a => a.StatusOfAdviceLineCaller)
.Include(a => a.AdviceLineCallSubjectMatter)
join ag in db.Agencies on a.AgencyNumber equals ag.AgencyNumber
join st in db.StatusOfAdviceLineCallers on a.StatusOfAdviceLineCallerID
equals st.StatusOfAdviceLineCallerID
join s in db.Staffs on a.StaffID equals s.StaffID
join sm in db.AdviceLineCallSubjectMatters on a.AdviceLineCallSubjectMatterID
equals sm.AdviceLineCallSubjectMatterID into grp
from sm in grp.DefaultIfEmpty()
where s.Employed == true
select new AdviceLineCallTotalViewModel()
{
AdviceLineCallID = a.AdviceLineCallID,
AdviceLineCallSubjectMatterID = sm.AdviceLineCallSubjectMatterID,
AdviceLineCallSubjectMatterDesc = sm.AdviceLineCallSubjectMatterDesc,
StatusOfAdviceLineCallerID = st.StatusOfAdviceLineCallerID,
StatusOfAdviceLineCallerDesc = st.StatusOfAdviceLineCallerDesc,
AgencyNumber = a.AgencyNumber,
AgencyNumberNameFacility = ag.AgencyNumberNameFacility,
CallDate = a.CallDate,
CallLength = a.CallLength,
Comments = a.Comments,
StaffID = a.StaffID,
LastName = s.LastName
};
When I debug and look at the SQL generated, I see:
SELECT
[Extent1].[AdviceLineCallID] AS [AdviceLineCallID],
[Extent5].[AdviceLineCallSubjectMatterID] AS [AdviceLineCallSubjectMatterID],
[Extent5].[AdviceLineCallSubjectMatterDesc] AS [AdviceLineCallSubjectMatterDesc],
[Extent3].[StatusOfAdviceLineCallerID] AS [StatusOfAdviceLineCallerID],
[Extent3].[StatusOfAdviceLineCallerDesc] AS [StatusOfAdviceLineCallerDesc],
[Extent1].[AgencyNumber] AS [AgencyNumber],
[Extent2].[AgencyNumberNameFacility] AS [AgencyNumberNameFacility],
[Extent1].[CallDate] AS [CallDate],
[Extent1].[CallLength] AS [CallLength],
[Extent1].[Comments] AS [Comments],
[Extent1].[StaffID] AS [StaffID],
[Extent4].[LastName] AS [LastName]
FROM [dbo].[AdviceLineCall] AS [Extent1]
INNER JOIN [dbo].[Agency] AS [Extent2] ON [Extent1].[AgencyNumber] = [Extent2].[AgencyNumber]
INNER JOIN [dbo].[StatusOfAdviceLineCaller] AS [Extent3] ON [Extent1].[StatusOfAdviceLineCallerID] = [Extent3].[StatusOfAdviceLineCallerID]
INNER JOIN [dbo].[Staff] AS [Extent4] ON [Extent1].[StaffID] = [Extent4].[StaffID]
INNER JOIN [dbo].[AdviceLineCallSubjectMatter] AS [Extent5] ON [Extent1].[AdviceLineCallSubjectMatterID] = [Extent5].[AdviceLineCallSubjectMatterID]
WHERE 1 = [Extent4].[Employed]
The last "INNER JOIN" should be a "LEFT OUTER JOIN" because of the lines:
join sm in db.AdviceLineCallSubjectMatters on a.AdviceLineCallSubjectMatterID equals sm.AdviceLineCallSubjectMatterID into grp
from sm in grp.DefaultIfEmpty()
Right???
NOTE: I included the "Include" statements after reading another post about why the "LEFT OUTER JOIN" is not being included. I get the same results with or without the "Includes."
I've used DefaultIfEmpty() in other, simpler queries before and have not run into this problem.
As an EF newbie, I'm not sure if I'm doing something wrong or if EF in my project got corrupted some how. I'm using EF 6.2.
EDIT:
I created a new Visual Studio Project and used the following code:
var adviceLineCallTotalViewModelList = from a in db.AdviceLineCalls
join ag in db.Agencies on a.AgencyNumber equals ag.AgencyNumber
join st in db.StatusOfAdviceLineCallers on a.StatusOfAdviceLineCallerID equals st.StatusOfAdviceLineCallerID
join s in db.Staffs on a.StaffID equals s.StaffID
join sm in db.AdviceLineCallSubjectMatters on a.AdviceLineCallSubjectMatterID equals sm.AdviceLineCallSubjectMatterID into grp
from sm_left in grp.DefaultIfEmpty()
where s.Employed == true
select new AdviceLineCallTotalViewModel()
{
AdviceLineCallID = a.AdviceLineCallID,
AdviceLineCallSubjectMatterID = sm_left == null ? 0 : sm_left.AdviceLineCallSubjectMatterID,
AdviceLineCallSubjectMatterDesc = sm_left == null ? String.Empty : sm_left.AdviceLineCallSubjectMatterDesc,
StatusOfAdviceLineCallerID = st.StatusOfAdviceLineCallerID,
StatusOfAdviceLineCallerDesc = st.StatusOfAdviceLineCallerDesc,
AgencyNumber = a.AgencyNumber,
AgencyNumberNameFacility = ag.AgencyNumberNameFacility,
CallDate = a.CallDate,
CallLength = a.CallLength,
Comments = a.Comments,
StaffID = a.StaffID,
LastName = s.LastName
};
This retrieves the correct number of rows (5104). It also correctly creates the last join as a LEFT OUTER JOIN:
LEFT OUTER JOIN [dbo].[AdviceLineCallSubjectMatter] AS [Extent5] ON [Extent1].[AdviceLineCallSubjectMatterID] = [Extent5].[AdviceLineCallSubjectMatterID]
However, this same line of code in my current project only returns 5 records, and the last join is incorrectly translated into an INNER JOIN.
Does this mean EF or something got corrupted in my current project? As a newbie to MVC and EF, I'm not sure what to do.
join sm in db.AdviceLineCallSubjectMattersandfrom sm in grp.DefaultIfEmpty()looks weird. Try to change the secondsm intosm_leftand int the select reference it likeAdviceLineCallSubjectMatterID = sm_left == null? 0 : sm_left.AdviceLineCallSubjectMatterIDAdviceLineCallSubjectMatterDesc = sm.AdviceLineCallSubjectMatterDesc,I get the correct count. NOTE: I'm new to Stack Overflow and "think" I'm using backticks correctly before and after my code in this comment. Maybe it will display as a code block when I click "Add Comment?"AdviceLineCallSubjectMatter.AdviceLineCallSubjectMatterIDis an int. So when I try something like your suggestion:AdviceLineCallSubjectMatterID = sm_left?.AdviceLineCallSubjectMatterID ?? null,, I get an error stating, "An expression tree lambda may not contain a null propagating operator," with red squiggles under:sm_left?.AdviceLineCallSubjectMatterID