【发布时间】:2015-04-29 13:22:47
【问题描述】:
我现在正在重构一个项目,页面上有很多非常相似的查询
db.WF_Process.Where(x=>x.WorkflowProcessState ==
(int)WorkflowProcessStateEnum.SubtitleFileVersion &&
x.WorkflowProcessSubState == (int)SubtitleFileProcessEnum.SubtitleQCReferred).Count();
db.WF_Process.Where(x=>x.WorkflowProcessState ==
(int)WorkflowProcessStateEnum.SubtitleFileVersion &&
x.WorkflowProcessSubState == (int)SubtitleFileProcessEnum.QCUserFailed).Count();
这会产生以下运行非常快的 SQL
SELECT
[GroupBy1].[A1] AS [C1]
FROM ( SELECT
COUNT(1) AS [A1]
FROM [dbo].[WF_Process] AS [Extent1]
WHERE (4 = [Extent1].[WorkflowProcessState]) AND (119 = [Extent1].[WorkflowProcessSubState])
) AS [GroupBy1]
//用100个不同的枚举值重复上述查询
为了稍微清理一下代码,我将其重构为以下方法
private int GetSubtitleProcessCount(Func<WF_Process, bool> predicate)
{
return
db.WF_Process.Where(x => x.WorkflowProcessState == (int)WorkflowProcessStateEnum.SubtitleFileVersion)
.Where(predicate)
.Count();
}
这样称呼
model.SubtitleQCReferred = GetSubtitleProcessCount(x=> x.WorkflowProcessSubState == (int)SubtitleFileProcessEnum.SubtitleQCReferred);
然而这会产生这个 SQL
SELECT
[Extent1].[ProcessID] AS [ProcessID],
[Extent1].[MaterialID] AS [MaterialID],
[Extent1].[VideoVersionID] AS [VideoVersionID],
[Extent1].[AudioVersionID] AS [AudioVersionID],
[Extent1].[TXVersionID] AS [TXVersionID],
[Extent1].[XMLVersionID] AS [XMLVersionID],
[Extent1].[SubtitleVersionID] AS [SubtitleVersionID],
[Extent1].[Progress] AS [Progress],
[Extent1].[ProcessStatusDescription] AS [ProcessStatusDescription],
[Extent1].[WorkflowProcessState] AS [WorkflowProcessState],
[Extent1].[WorkflowProcessSubState] AS [WorkflowProcessSubState],
[Extent1].[ProcessState] AS [ProcessState],
[Extent1].[ProcessStateDateLastModified] AS [ProcessStateDateLastModified],
[Extent1].[DateCreated] AS [DateCreated],
[Extent1].[DateLastChecked] AS [DateLastChecked],
[Extent1].[SleepUntil] AS [SleepUntil],
[Extent1].[LongRunningProcessID] AS [LongRunningProcessID]
FROM [dbo].[WF_Process] AS [Extent1]
WHERE 4 = [Extent1].[WorkflowProcessState]
它检索整个记录集,然后在代码中执行计数。
我假设这与第二个 where 子句有关。这是为什么呢?
有什么方法可以保持我正在使用的模式(稍作修改),以便生成体面的 SQL?
【问题讨论】:
-
从外观上看,您的代码应该生成正确的 sql 以在 SQL 上而不是在内存中运行计数。您的谓词之一导致它在代码中枚举,因为由于某种原因它无法转换为 sql,但它们看起来应该是有效的。
-
尝试使用
Func<WF_Process>而不是Expression<Func<WF_Process>>。您使用的是 linq to objects。 -
哦,我知道为什么。因为
Where(Func<>)是内存扩展。你想要Where(Expression<Func<>>) -
出于好奇。请注意为什么会有数百次以这种方式检索的计数,如果它们都匹配同一个字段,或者您给出的两个示例只是巧合?使用 group by 并一次获取所有计数然后将计数从内存集合中分配给模型应该更有效?
-
那么对 db 的 1 次查询不应该足够吗?哪个按字幕和workflowprocesssubstate分组,并返回workflowprocesssubstate编号和计数?
标签: sql .net sql-server linq