实体框架未正确将C#转换为SQL

时间:2017-11-27 16:44:55

标签: c# entity-framework linq linq-to-entities

我一直在使用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的新手,我不知道该怎么做。

2 个答案:

答案 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类,并且没有添加必需的数据注释。