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

时间:2011-06-30 08:59:56

标签: c# entity-framework-4.1

理解为什么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])中的列。

2 个答案:

答案 0 :(得分:4)

[Extent2]被使用 - 它是SQL的WHERE的一部分。查询的结果将是正确的,但性能可能会更糟。我不认为SQL服务器会优化它以摆脱不必要的左连接。

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

答案 1 :(得分:1)

在我的结尾处遇到类似的问题,在不需要的情况下生成多个JOIN(即,可以很容易地将SQL查询更改为仅包含一个INNER JOIN到父表而不是同时具有INNER和LEFT JOIN到父表)。

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

WHERE tbl1.ParentID = 1或tbl2.ParentID IN(2,3)

这两个问题都已在2011年6月的CTP套餐中得到纠正: Entity framework CTP - June 2011