我在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')
答案 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();