如何强制 LINQ to SQL 评估数据库中的整个查询?
我有一个可以完全转换为 SQL 的查询。由于未知原因,LINQ 决定最后一个 Select()
在 .NET 中(而不是在数据库中)执行,这会导致针对数据库运行大量额外的 SQL 查询(每个项目)。
实际上,我发现了一种“奇怪”的方式来强制完全转换为 SQL:
我有一个查询(这是一个非常简化的版本,但仍然无法按预期工作):
MainCategories.Select(e => new
{
PlacementId = e.CatalogPlacementId,
Translation = Translations.Select(t => new
{
Name = t.Name,
// ...
}).FirstOrDefault()
})
它将生成大量 SQL 查询:
SELECT [t0].[CatalogPlacementId] AS [PlacementId]
FROM [dbo].[MainCategories] AS [t0]
SELECT TOP (1) [t0].[Name]
FROM [dbo].[Translations] AS [t0]
SELECT TOP (1) [t0].[Name]
FROM [dbo].[Translations] AS [t0]
...
但是,如果我附加另一个 Select()
,它只复制所有成员:
.Select(e => new
{
PlacementId = e.PlacementId,
Translation = new
{
Name = e.Translation.Name,
// ...
}
})
它将编译成单个 SQL 语句:
SELECT [t0].[CatalogPlacementId] AS [PlacementId], (
SELECT [t2].[Name]
FROM (
SELECT TOP (1) [t1].[Name]
FROM [dbo].[Translations] AS [t1]
) AS [t2]
) AS [Name]
FROM [dbo].[MainCategories] AS [t0]
有什么线索吗? 如何强制 LINQ to SQL 更通用地生成单个查询(无需第二次复制 Select()
)?
注意: 我已经更新为查询以使其变得非常简单。
PS:只是,我得到的想法是使用类似的模式后处理/转换查询(添加另一个Select()
)。
I have a query which is fully translatable to SQL. For unknown reasons LINQ decides the last Select()
to execute in .NET (not in the database), which causes to run a lot of additional SQL queries (per each item) against database.
Actually, I found a 'strange' way to force the full translation to SQL:
I have a query (this is a really simplified version, which still does not work as expected):
MainCategories.Select(e => new
{
PlacementId = e.CatalogPlacementId,
Translation = Translations.Select(t => new
{
Name = t.Name,
// ...
}).FirstOrDefault()
})
It will generates a lot of SQL queries:
SELECT [t0].[CatalogPlacementId] AS [PlacementId]
FROM [dbo].[MainCategories] AS [t0]
SELECT TOP (1) [t0].[Name]
FROM [dbo].[Translations] AS [t0]
SELECT TOP (1) [t0].[Name]
FROM [dbo].[Translations] AS [t0]
...
However, if I append another Select()
which just copies all members:
.Select(e => new
{
PlacementId = e.PlacementId,
Translation = new
{
Name = e.Translation.Name,
// ...
}
})
It will compile it into a single SQL statement:
SELECT [t0].[CatalogPlacementId] AS [PlacementId], (
SELECT [t2].[Name]
FROM (
SELECT TOP (1) [t1].[Name]
FROM [dbo].[Translations] AS [t1]
) AS [t2]
) AS [Name]
FROM [dbo].[MainCategories] AS [t0]
Any clues why? How to force the LINQ to SQL to generate a single query more generically (without the second copying Select()
)?
NOTE: I've updated to query to make it really simple.
PS: Only, idea I get is to post-process/transform queries with similar patterns (to add the another Select()
).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
当您在
MyQuery
中调用SingleOrDefault
时,您正在执行查询,并将结果加载到客户端中。SingleOrDefault 返回
IEnumerable
,它不再是IQueryable
。此时您已强制执行它将在客户端上执行所有进一步处理 - 它无法再执行 SQL 组合。When you call
SingleOrDefault
inMyQuery
, you are executing the query at that point which is loading the results into the client.SingleOrDefault returns
IEnumerable<T>
which is no longer anIQueryable<T>
. You have coerced it at this point which will do all further processing on the client - it can no longer perform SQL composition.不完全确定发生了什么,但我发现你编写这个查询的方式非常“奇怪”。我会这样写,并怀疑这会起作用:
我总是尝试将
from
部分(数据源的选择)与select
部分(投影到目标)分开我发现它也更容易阅读/理解,而且它通常也适用于大多数 linq 提供程序。Not entirely sure what is going on, but I find the way you wrote this query pretty 'strange'. I would write it like this, and suspect this will work:
I always try to separate the
from
part (selection of the datasources) from theselect
part (projection to your target type. I find it also easier to read/understand, and it generally also works better with most linq providers.您可以按如下方式编写查询以获得所需的结果:
据我所知,这是由于 LINQ 投影查询的方式所致。我认为当它看到嵌套的
Select
时,它不会将其投影到多个子查询中,因为本质上这就是所需要的,因为 IIRC 你不能使用子查询中的多个返回列在 SQL 中,因此 LINQ 将其更改为每行查询。带有列访问器的 FirstOrDefault 似乎是对 SQL 中发生的情况的直接转换,因此 LINQ-SQL 知道它可以编写子查询。第二个
Select
必须投影查询,类似于我上面编写的方式。如果不深入反射器,就很难确认。一般来说,如果我需要选择许多列,我会使用let
语句,如下所示:You can write the query as follows to get the desired result:
As far as i'm aware, it's due to how LINQ projects the query. I think when it see's the nested
Select
, it will not project that into multiple sub-queries, as essentially that would be what would be needed, as IIRC you cannot use multiple return columns from a sub-query in SQL, so LINQ changes this to a query-per-row.FirstOrDefault
with a column accessor seems to be a direct translation to what would happen in SQL and therefore LINQ-SQL knows it can write a sub-query.The second
Select
must project the query similar to how I have written it above. It would be hard to confirm without digging into a reflector. Generally, if I need to select many columns, I would use alet
statement like below: