我一直在使用Linq to SQL,并已开始将Entity Framework用于新项目。在将代码合并到Visual Studio中之前,我使用LinqPad来测试我的代码。在VS中调试时,我注意到我的计数不同。当我检查我的代码在VS中创建的SQL时,我注意到它没有正确翻译。
我在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
};
当我调试并查看生成的SQL时,我看到:
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]
最后一次" INNER JOIN"应该是一个" LEFT OUTER JOIN"由于行:
join sm in db.AdviceLineCallSubjectMatters on a.AdviceLineCallSubjectMatterID equals sm.AdviceLineCallSubjectMatterID into grp
from sm in grp.DefaultIfEmpty()
右???
注意:我包含了" Include"在阅读了另一篇关于为什么" LEFT OUTER JOIN"不包括在内。无论有没有"包括。"
,我都会得到相同的结果我之前在其他更简单的查询中使用过DefaultIfEmpty(),但没有遇到过这个问题。
作为一名EF新手,我不确定我是否做错了什么,或者我的项目中的EF是否被破坏了。我使用EF 6.2。
编辑:
我创建了一个新的Visual Studio项目并使用了以下代码:
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
};
这将检索正确的行数(5104)。它还正确地创建了最后一个连接作为LEFT OUTER JOIN:
LEFT OUTER JOIN [dbo].[AdviceLineCallSubjectMatter] AS [Extent5] ON [Extent1].[AdviceLineCallSubjectMatterID] = [Extent5].[AdviceLineCallSubjectMatterID]
但是,我当前项目中的同一行代码只返回5条记录,最后一个连接被错误地转换为INNER JOIN。
这是否意味着我当前项目中的EF或某些内容已损坏?作为MVC和EF的新手,我不知道该怎么做。
答案 0 :(得分:1)
更改
join sm in db.AdviceLineCallSubjectMatters ...
from sm in grp.DefaultIfEmpty() ...
....
select
AdviceLineCallSubjectMatterID = sm.AdviceLineCallSubjectMatterID
进入
join sm in db.AdviceLineCallSubjectMatters ...
from sm_left in grp.DefaultIfEmpty() ...
....
select
AdviceLineCallSubjectMatterID = sm_left == null? 0 : sm_left.AdviceLineCallSubjectMatterID
根据.net框架版本,您可以将select null检查更改为更干净的方式(查看@Jacob Proffitt评论)
答案 1 :(得分:0)
我找到了问题的原因以及为什么相同的C#代码被不同地翻译成SQL,这一切都与必需的数据注释有关。
表AdviceLineCallSubjectMatter是DB的新增功能。所以只有新的AdviceLineCall记录才会有一个AdviceLineCallSubjectMatterID,所以我把它作为一个可以为空的int。
某些AdviceLineCall字段是"必需的,"和新的int?使用Required数据注释将AdviceLineCallSubjectMatterID添加到我的AdviceLineCall Model类中。
public partial class AdviceLineCall
{
.
.
.
[Required(ErrorMessage = "Subject Matter is required")]
[DisplayName("Subject Matter")]
public int? AdviceLineCallSubjectMatterID { get; set; }
.
.
.
}
public partial class AdviceLineCallSubjectMatter
{
public AdviceLineCallSubjectMatter()
{
AdviceLineCalls = new HashSet<AdviceLineCall>();
}
[DisplayName("Subject Matter")]
public int AdviceLineCallSubjectMatterID { get; set; }
[StringLength(3)]
[DisplayName("Subject Matter")]
public string AdviceLineCallSubjectMatterDesc { get; set; }
public virtual ICollection<AdviceLineCall> AdviceLineCalls { get; set; }
}
}
当我在AdviceLineCall Model类中注释掉Required数据注释时,我的C#被转换为期望的SQL,并在AdviceLineCallSubjectMatter上使用LEFT OUTER JOIN。
我不确定为什么必需的数据注释会产生这种影响???
注意:在我为测试相同查询而创建的临时项目中,我通过Code First From DB创建了DB Context和Model类,并且没有添加必需的数据注释。