实体框架生成的SQL问题(同一表上有多个联接)

本文关键字:框架 SQL 问题 实体 | 更新日期: 2023-09-27 18:00:50

理解EF(4.1(生成特定SQL查询的原因有点问题。如下:

基本上我有这两类

public class Rota
{
    public int RotaId { get; set; }
    public int RotaGroupId { get; set; }
    public virtual RotaGroup RotaGroup { get; set; }
    public int EmployeeId { get; set; }
    public virtual Employee Employee { get; set; }
    ...

public class RotaGroup
{
    public int RotaGroupId { get; private set; }
    public bool IsCurrentRota { get; set; }
    ...

rota的映射如下:

HasKey(r => r.RotaId);
Property(r=>r.RotaId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
HasRequired(r => r.RotaGroup).WithMany()
                             .HasForeignKey(r => r.RotaGroupId)
                             .WillCascadeOnDelete(false);
HasRequired(r => r.Employee).WithMany()
                            .HasForeignKey(r => r.EmployeeId)
                            .WillCascadeOnDelete(false);

好的。现在下面的linq查询:

_context.Rotas.Include(r => r.RotaGroup)
              .Where(r => r.EmployeeId == 1 && r.RotaGroup.IsCurrentRota)
              .ToList();

生成以下SQL:

SELECT ...columns...
FROM [dbo].[Rota] AS [Extent1]
INNER JOIN [dbo].[RotaGroup] AS [Extent2] ON [Extent1].[RotaGroupId] = [Extent2][RotaGroupId]
LEFT OUTER JOIN [dbo].[RotaGroup] AS [Extent3] ON [Extent1].[RotaGroupId] = [Extent3].[RotaGroupId] 
WHERE ([Extent2].[IsCurrentRota] = 1) AND ([Extent1].[MyIgluUserId] = 1

我相信你能看到这个问题。为什么,哦,为什么它加入了rotaGroup(应该加入(,然后进行左外加入?此外,不使用[Extent2](内部联接(中的列。仅使用来自左侧外部联接位([Extent3](的列。

实体框架生成的SQL问题(同一表上有多个联接)

[Extent2]被使用-它是SQL的WHERE的一部分。查询的结果将是正确的,但性能可能会更差。我不认为SQL server会对此进行优化以消除不必要的左联接。

EF就是这样生成查询的。据我所知,EF不跟踪实体集的使用,所以这两个查询部分Include(r => r.RotaGroup)Where(r => r.RotaGroup.IsCurrentRota)彼此不相关。左联接是Include的结果,内联接是Where的结果。您可以尝试修改查询,使Include的部分是过滤的子查询,但我怀疑它的工作方式会有所不同。

我遇到了一个类似的问题,即当不需要多个JOIN时会生成多个JOINN(即,SQL查询可以很容易地更改为只包含一个父表的INNER JOIN,而不是同时包含一个INNER和LEFT JOIN(。

我的问题还涉及测试多个值的相等性(例如,where child.ParentID==1||child.Parent ID=2=|child.PParentID==3(,这创建了一个混乱的where子句(其中tbl1和tbl2是添加到SELECT语句中的INNER和LEFT联接表(:

其中tbl1.ParentID=1或tbl2.ParentID在(2,3(中

这两个问题都已在2011年6月的CTP包中得到纠正:实体框架CTP-2011年6月