【发布时间】:2018-02-02 15:39:35
【问题描述】:
显然我错过了 LINQ to entity 的工作原理。希望你们中的一个可以教育我。
请在本地尝试以下操作,如果您看到相同的结果,请告诉我。这里真的很奇怪……
让我们看一个使用导航属性的非常简单的 LINQ 表达式。
这是在 LinqPad 中的 C# 语句中生成的。
var result = (from ge in group_execution
where ge.automation_sequences.project.client_id == 1 && ge.parent_group_exec_id != null
select new
{
ge.id,
ge.parent_group_exec_id,
ge.automation_sequences.project.client_id
});
result.Dump();
或者,我们可以使用连接...这将导致同样糟糕的结果,但让我们继续...
var result = (from ge in group_execution
join aseq in automation_sequences on ge.automation_sequence_id equals aseq.id
join p in project on aseq.project_id equals p.id
where p.client_id == 1 && ge.parent_group_exec_id != null
select new
{
ge.id,
ge.parent_group_exec_id,
p.client_id
});
result.Dump();
这些非常简单的 LINQ 表达式生成以下 SQL:
SELECT
[Filter1].[id1] AS [id],
[Filter1].[parent_group_exec_id] AS [parent_group_exec_id],
[Extent5].[client_id] AS [client_id]
FROM (SELECT [Extent1].[id] AS [id1], [Extent1].[automation_sequence_id] AS [automation_sequence_id], [Extent1].[parent_group_exec_id] AS [parent_group_exec_id]
FROM [dbo].[group_execution] AS [Extent1]
INNER JOIN [dbo].[automation_sequences] AS [Extent2] ON [Extent1].[automation_sequence_id] = [Extent2].[id]
INNER JOIN [dbo].[project] AS [Extent3] ON [Extent2].[project_id] = [Extent3].[id]
WHERE ([Extent1].[parent_group_exec_id] IS NOT NULL) AND (1 = [Extent3].[client_id]) ) AS [Filter1]
LEFT OUTER JOIN [dbo].[automation_sequences] AS [Extent4] ON [Filter1].[automation_sequence_id] = [Extent4].[id]
LEFT OUTER JOIN [dbo].[project] AS [Extent5] ON [Extent4].[project_id] = [Extent5].[id]
这让我很困惑。对于我的生活,我无法理解为什么 LINQ 会这样做。太可怕了,看看执行计划:
现在让我们在 SSMS 中手动清理它并查看正确的 SQL 和执行计划:
好多了,但是我们如何让 LINQ 以这种方式运行?
还有人看到这个吗?有没有其他人看到过这个并纠正过它,如果有,如何纠正?
感谢您对此进行调查。
更新,正在尝试修复 Chris Schaller:
var result = (from ge in group_execution
select new
{
ge.id,
ge.parent_group_exec_id,
ge.automation_sequences.project.client_id
}).Where(x=>x.client_id == 1 && x.parent_group_exec_id != null);
result.Dump();
让你们都知道我正在通过 SQL Server Profiler 监控 SQL。如果有人知道这样做有任何问题,请告诉我。
更新,一个 JOINS 的修复,但不是导航属性,一个原因,但是为什么?
这是您的解决方案:
var result = (from ge in group_execution.Where(x=>x.parent_group_exec_id != null)
join aseq in automation_sequences on ge.automation_sequence_id equals aseq.id
join p in project on aseq.project_id equals p.id
where p.client_id == 1// && ge.parent_group_exec_id != null
select new
{
ge.id,
ge.parent_group_exec_id,
p.client_id
});
result.Dump();
Null 检查不应导致框架像这样混乱。为什么我必须这样写?这对我来说似乎是框架中的一个缺陷。它会使我的动态表达式更难写,但也许我能找到一种方法。
导航属性仍然一团糟……所以我仍然很伤心。下图:
var result = (from ge in group_execution.Where(x=>x.parent_group_exec_id != null)
where ge.automation_sequences.project.client_id == 1// && ge.parent_group_exec_id != null
select new
{
ge.id,
ge.parent_group_exec_id,
ge.automation_sequences.project.client_id
});
result.Dump();
【问题讨论】:
-
顺便说一句,这些优化是 SQL 查询优化器/执行计划生成器的责任。 EF(以及任何开发人员)应提供有效 SQL 语句。那条 SQL 语句怎么不重要 - 现在 RBO 已经不复存在了。
-
尝试着眼于实际问题。此查询形状是否会给您带来任何问题 w.r.t.表现?众所周知,EF(或任何 ORM)不会产生人类会仔细构建的查询。但通常他们做得不错。此外,EF 始终致力于更好地生成查询,因此在下一个版本中,您自己的优化可能会变得无用(甚至可能产生不利影响)。
标签: asp.net sql-server entity-framework linq linq-to-entities