为什么这些查询会生成不同的sql?

时间:2014-04-07 07:49:49

标签: linq entity-framework

我在Entity框架中遇到linq查询问题。我在导航属性的字段上查询。问题是生成的sql不是最佳的。下面的例子是简化的,实际上我试图传递一个表达式树,这就是为什么带有let绑定的第二个查询不是一个充分的解决方案,即使生成的sql是我想要的。

总而言之,我有两个问题:

为什么生成的sql不同?有没有办法生成一个SQL查询,它不会为表达式树的每个条件创建一个连接?

更新:我意识到我在第一个查询时包含("证券")而不是我第一次发布问题时的第二个查询,但它并没有改变标准的应用方式,只选择了哪些列。

var qry = db.Positions                   
    .Where(criteria)
    .ToList();

var qry1 = (from p in db.Positions
            where p.Security.Country == "NO" || p.Security.Country == "US" || p.Security.Country == "GB"
            select p).ToList();

var qry2 = (from p in db.Positions
           let s = p.Security
           where s.Country == "NO" || s.Country == "US" || s.Country == "GB"
           select p).ToList();


--qry1
SELECT 
    [Extent1].* --All columns from tblPositions
    FROM     [dbo].[tblPositions] AS [Extent1]
    LEFT OUTER JOIN [dbo].[tblSecurities] AS [Extent2] ON ([Extent2].[SecurityType] IN (1,2..)) AND ([Extent1].[Security] = [Extent2].[SecuritySeq])
    LEFT OUTER JOIN [dbo].[tblSecurities] AS [Extent3] ON ([Extent3].[SecurityType] IN (1,2..)) AND ([Extent1].[Security] = [Extent3].[SecuritySeq])
    LEFT OUTER JOIN [dbo].[tblSecurities] AS [Extent4] ON ([Extent4].[SecurityType] IN (1,2..)) AND ([Extent1].[Security] = [Extent4].[SecuritySeq])
    LEFT OUTER JOIN [dbo].[tblSecurities] AS [Extent5] ON ([Extent5].[SecurityType] IN (1,2..)) AND ([Extent1].[Security] = [Extent5].[SecuritySeq])
    WHERE [Extent2].[Country] = 'NO' OR [Extent3].[Country] = 'US' OR [Extent4].[Country] = 'GB'

--qry2
SELECT 
    [Extent1].*
    FROM  [dbo].[tblPositions] AS [Extent1]
    LEFT OUTER JOIN [dbo].[tblSecurities] AS [Extent2] ON ([Extent2].[SecurityType] IN (1,2..)) AND ([Extent1].[Security] = [Extent2].[SecuritySeq])
    WHERE [Extent2].[Country] IN ('NO','US','GB')

1 个答案:

答案 0 :(得分:0)

在您的第一个查询中

var qry1 = (from p in db.Positions.Include("Security")
           where p.Security.Country == "NO" 
             || p.Security.Country == "US"
             || p.Security.Country == "GB"
           select p).ToList();

似乎您认为实体框架具有神奇的力量,并且可以推断生成的表达式树中的每个or语句都在同一个对象上,并且它可以将它们组合成一个包含。到目前为止,它并不那么聪明。

此外,两个查询返回的行都不相同。第二个还需要一个include,以包含来自安全性的行(如果需要)。否则你可以从第一个查询中删除它们(include只表示返回行,它与where子句过滤行的能力无关。)

或者使其更加面向对象和可读性。

var allowedCountries = new List<string>() { "NO, "US", "GB" };

var qry1 = (from p in db.Positions
            // I'm not sure if this is exactly correct
            where p.Security.Country in allowedCountries
            select p).ToList();

或Lambda(我更熟悉)

var qry1 = db.Positions
           .Where(p => allowedCountries.Contains(p.Security.Country))
           .ToList();