为什么用几乎相同的表结构生成不同的T-SQL

本文关键字:T-SQL 结构 为什么 | 更新日期: 2023-09-27 18:10:41

这真的让我疯了,我不明白为什么希望有人能给我一点提示,为什么它的行为如此。我有4张表

这2个表的第一组,并能够给我一个干净和漂亮的T-SQL(从这个链接的示例)

public class Standard
{
    public Standard()
    {
        Students = new List<Student>();
    }
    public int StandardId { get; set; }
    public string StandardName { get; set; }
    public string Description { get; set; }
    public virtual ICollection<Student> Students { get; set; }
}
public class Student
{
    public Student() { }
    public int StudentId { get; set; } 
    public string StudentName { get; set; } 
    public virtual Standard Standard { get; set; }
}

与上面的表和我使用这个 LINQ

List<Student> student = context.student.ToList();

var r = from ord in context.student.Include("standard") 
        select ord;

输出

SELECT 
[Extent1].[StudentId] AS [StudentId], 
[Extent1].[StudentName] AS [StudentName], 
[Extent2].[StandardId] AS [StandardId], 
[Extent2].[StandardName] AS [StandardName], 
[Extent2].[Description] AS [Description]
FROM  [dbo].[Students] AS [Extent1]
LEFT OUTER JOIN [dbo].[Standards] AS [Extent2] ON [Extent1].[Standard_StandardId] = [Extent2].[StandardId]

但与第二组

public partial class Cust_ProfileTbl
{
    public Cust_ProfileTbl()
    {
        balance = new List<BP_BalanceTbl>();
    }
    [Key]
    public virtual long bintAccountNo { get; set; }
    public string varCardNo { get; set; }

    public virtual ICollection<BP_BalanceTbl> balance { get; set; }

}

public class BP_BalanceTbl
{
    public BP_BalanceTbl() { }
    public virtual long bintAccountNo { get; set; }
    [Key]
    public int intid { get; set; }
    public virtual Cust_ProfileTbl profile { get; set; }
}
LINQ
List<Cust_ProfileTbl> profile = context.profile.ToList();
var rs = from ord in context.profile.Include("balance")
        select ord;

SELECT 
[Project1].[C1] AS [C1], 
[Project1].[bintAccountNo] AS [bintAccountNo], 
[Project1].[varCardNo] AS [varCardNo], 
[Project1].[C2] AS [C2], 
[Project1].[intid] AS [intid], 
[Project1].[bintAccountNo1] AS [bintAccountNo1]
FROM ( SELECT 
    [Extent1].[bintAccountNo] AS [bintAccountNo], 
    [Extent1].[varCardNo] AS [varCardNo], 
    1 AS [C1],      --Why it generate this>?
    [Extent2].[intid] AS [intid], 
    [Extent2].[bintAccountNo] AS [bintAccountNo1], 
    CASE WHEN ([Extent2].[intid] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C2] --Why it generate this>?
    FROM  [dbo].[Cust_ProfileTbl] AS [Extent1]
    LEFT OUTER JOIN [dbo].[BP_BalanceTbl] AS [Extent2] ON [Extent1].[bintAccountNo] = [Extent2].[bintAccountNo]
)  AS [Project1]
ORDER BY [Project1].[bintAccountNo] ASC, [Project1].[C2] ASC

  1. 为什么在第二个LINQ生成C1?
  2. 为什么在第二个LINQ中有这个行CASE WHEN ([Extent2]。[intid] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C2]——为什么生成这个?
  3. 为什么第二个输出如此复杂?

为什么用几乎相同的表结构生成不同的T-SQL

  1. C1列似乎与查询无关-它可能是自动发生的优化或保护,以便LINQ不会意外创建无效的东西-或者可能是为了第一行不会无意中具有NULL值。

  2. C2列是作为对空值的保护而生成的,因为该值被归为主键(这意味着它不能为空)。由于您正在执行LEFT OUTER JOIN,因此左侧的值可能没有连接记录-但仍然必须显示LEFT信息的有效行。

  3. 查询只是看起来更复杂,因为它在选择结果之前在临时表中构造了这些额外的信息。它可能以这种方式布局查询,因为这是它知道如何通过代码生成查询的唯一方式——或者它可能足够聪明,知道这个查询对于查询引擎来说稍微更优一些(我可能不会打赌)。

在第一种情况下,你正在做包含简单的导航属性(因此,它可以通过简单的左外连接来完成,响应中的每一行将被物化为结果中的实体),在第二种情况下,包含collection,因此result中的几行应该合并到单个实体及其collection属性中。因此,SQL查询必须以以下方式编写:1. 要合并到单个实体中的所有行将按顺序获取2. 方便检测组边界的处理3.减少数据重复在这个简单的例子中,生成的SQL的某些部分可以被消除,但是当包含几个集合属性时,它们被用于更复杂的查询,等等。