CompiledQuery与Plain Linq SQL生成

时间:2009-03-31 16:42:53

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

所以我正在对我的SQLServer数据库的不同方法进行一些分析。我做了vanilla TSQL,CompiledQuery和一个未编译的Linq语句。

表演按照预期顺序排列,但我在发现后两者时发现了一些奇怪的事情。

CompiledQuery生成的SQL比普通旧语句生成的SQL要好得多。

本地SQLExpress数据库; table被称为'foreignTable',ColumnA是int,主键(索引); ColumnB是随机int。

Func<testingDatabaseEntities1, int, int> GetByPK = CompiledQuery.Compile((testingDatabaseEntities1 ft, int key) 
  => (ft.foreignTable.Where(x => x.ColumnA == key).FirstOrDefault().ColumnB));

生成

SELECT 
[Project1].[ColumnB] AS [ColumnB]
FROM   ( SELECT cast(1 as bit) AS X ) AS [SingleRowTable1]
LEFT OUTER JOIN  (SELECT TOP (1) 
    [Extent1].[ColumnB] AS [ColumnB]
    FROM [dbo].[foreignTable] AS [Extent1]
    WHERE [Extent1].[ColumnA] = @p__linq__1 ) AS [Project1] ON 1 = 1

对于生成的代码,确实不是可怕。

但是当我做普通的Linq声明时:

entity.foreignTable.Where(x => x.ColumnA == searchForMe).FirstOrDefault().ColumnB

它生成:

SELECT 
[Limit1].[C1] AS [C1], 
[Limit1].[ColumnA] AS [ColumnA], 
[Limit1].[ColumnB] AS [ColumnB], 
[Limit1].[FKColumn] AS [FKColumn]
FROM ( SELECT TOP (1) 
    [Extent1].[ColumnA] AS [ColumnA], 
    [Extent1].[ColumnB] AS [ColumnB], 
    [Extent2].[FKColumn] AS [FKColumn], 
    1 AS [C1]
    FROM  [dbo].[foreignTable] AS [Extent1]
    LEFT OUTER JOIN (SELECT 
      [Table_2].[FKColumn] AS [FKColumn], 
      [Table_2].[SomeText] AS [SomeText]
      FROM [dbo].[Table_2] AS [Table_2]) AS [Extent2] ON [Extent1].[ColumnA] = [Extent2].[FKColumn]
    WHERE [Extent1].[ColumnA] = @p__linq__7
)  AS [Limit1]

这很糟糕。

所以我想问题是:是否有可能将常规Linq给予实体与CompiledQuery相同数量的SQL suckiness?

2 个答案:

答案 0 :(得分:5)

您要比较的查询不一样。第一个编译的查询返回一个属性而不返回任何其他属性它永远不会返回任何不同。第二个返回一个您取消引用然后访问其属性的实体实例。当查询执行时,它无法知道您只想查看一个属性。

您可以从非编译查询中获取相同SQL的一种方法(未经测试)是投影到匿名类型:

var b = (from e in entity.foreignTable.
         where ColumnA == searchForMe
         select new 
         {
            ColumnB = e.ColumnB
         }).FirstOrDefault().ColumnB;

答案 1 :(得分:3)

编译的查询正在进行额外的工作,因为预计您将多次使用该查询。如果这就是您所追求的,那么只需坚持编译查询。

在这种特定情况下,您想要这样做:

entity.foreignTable
    .Where(x => x.ColumnA == searchForMe)
    .Select(x=>x.ColumnB)
    .FirstOrDefault();

这不完全相同,但它肯定会使查询更符合您的预期(仅检索ColumnB)。执行FirstOrDefault将为您提供实例,因此在linq2sql查询之后会发生.ColumnB。这也会导致行为上的差异,因为你的版本会因为空引用而失败,而这个新查询会给出ColumnB的默认值(null或特定值取决于ColumnB定义)。