尝试在LINQ查询中实现条件(使用Entityframework)会创建奇怪的查询。在某些情况下,即使阈值设置为180秒,这些查询也会超时:
List<LogEntity> dataList = db.LogEntities.Where(x =>
x.Source == "Source" &&
(String.IsNullOrEmpty(from) || x.EventDate >= cFrom) &&
(String.IsNullOrEmpty(to) || x.EventDate <= cTo) &&
(String.IsNullOrEmpty(uid) || x.DomainUserLogin == uid) &&
(String.IsNullOrEmpty(cid) || x.CaseReference == cid) &&
(String.IsNullOrEmpty(searchtext) || x.Message.Contains(searchtext)))
.OrderByDescending(y => y.EventDate)
.Take(500)
.ToList<LogEntity>();
if语句稍微不那么优雅,我没有遇到任何问题,查询会在几秒钟后返回:
IQueryable<LogEntity> data = db.LogEntities.Where(x => x.Source == "Source");
if (!String.IsNullOrEmpty(from))
data = data.Where(x => x.EventDate >= cFrom);
if (!String.IsNullOrEmpty(to))
data = data.Where(x => x.EventDate <= cTo);
if (!String.IsNullOrEmpty(uid))
data = data.Where(x => x.DomainUserLogin == uid);
if (!String.IsNullOrEmpty(cid))
data = data.Where(x => x.CaseReference == cid);
if (!String.IsNullOrEmpty(searchtext))
data = data.Where(x => x.Message.Contains(searchtext));
data = data.OrderByDescending(x => x.EventDate).Take(500);
List<LogEntity> dataList = data.ToList<LogEntity>();
条件语句全部来自查询字符串,这就是为什么它们有时可能带有值而有时不带有值。
使用像
这样的三元运算符时会出现同样的问题...Where(x => truth ? x.something == somevalue : x.something == anothervalue)
有没有合理的解释为什么这些内联条件的表现如此糟糕?
答案 0 :(得分:2)
当您在EF数据库上使用LINQ编写查询时,它们看起来非常自然但在幕后有查询转换器,它解析您的LINQ查询并将其拆分为两部分:一部分在sql服务器上执行,另一部分在客户端上使用只是LINQ扩展。
当您使用查询转换程序无法转换为SQL的某个表达式(例如某些.NET函数)时,它会最小化数据过滤,您最终可能会将整个数据表下载到客户端并对其进行过滤。
在您写的第一个查询中,您使用(String.IsNullOrEmpty(from) || x.EventDate >= cFrom)
; “from”是LogEntities的外部,翻译人员无法对其值以及如何计算记录进行任何假设。因此,最有可能的是,您只需将完整的LogEntities下载到客户端并将其过滤到客户端。如果记录数量很大,您将收到超时错误。
在第二个查询中,您加入了明确转换为sql的简单表达式Where(x => x.DomainUserLogin == uid);
。因此,您可以获得正确的sql查询,该查询可以过滤sql server端的大多数记录。
您可以使用SQL分析器或VS工具(取决于VS版本,或启用EF中的日志记录以查看已执行的实际查询。