LINQ to Entities 条件语句给出奇怪的结果
LINQ to Entities conditionals give weird results
尝试在 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 语句,我没有遇到任何问题,查询 return 在几秒钟内:
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)
对于为什么这些内联条件执行得如此糟糕,是否有任何合理的解释?
当您在 EF 数据库上使用 LINQ 编写查询时,它们看起来非常自然,但在幕后有查询翻译器解析您的 LINQ 查询并将其拆分为 2 parts:one 在 sql 上执行服务器,另一个 - 在仅使用 LINQ 扩展的客户端上。
当您使用查询转换器无法转换为 SQL 的某些表达式(例如某些 .NET 函数)时,它会最小化数据过滤,您最终可能会下载整个数据 table客户端并对其进行过滤。
在您写的第一个查询中,您使用(String.IsNullOrEmpty(from) || x.EventDate >= cFrom)
; "from" 在 LogEntities 外部,翻译器无法对其值以及如何计算记录进行任何假设。因此,很可能您只是将完整的 LogEntities 下载到客户端并将其过滤到客户端。如果记录数很大,你会得到超时错误。
在第二个查询中,您加入了简单表达式 Where(x => x.DomainUserLogin == uid);
,该表达式清楚地翻译为 sql。因此,您得到了正确的 sql 查询,该查询在 sql 服务器端过滤了大多数记录。
您可以使用 SQL 探查器或 VS 工具(取决于 VS 版本,或启用在 EF 中登录以查看执行的实际查询。
尝试在 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 语句,我没有遇到任何问题,查询 return 在几秒钟内:
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)
对于为什么这些内联条件执行得如此糟糕,是否有任何合理的解释?
当您在 EF 数据库上使用 LINQ 编写查询时,它们看起来非常自然,但在幕后有查询翻译器解析您的 LINQ 查询并将其拆分为 2 parts:one 在 sql 上执行服务器,另一个 - 在仅使用 LINQ 扩展的客户端上。
当您使用查询转换器无法转换为 SQL 的某些表达式(例如某些 .NET 函数)时,它会最小化数据过滤,您最终可能会下载整个数据 table客户端并对其进行过滤。
在您写的第一个查询中,您使用(String.IsNullOrEmpty(from) || x.EventDate >= cFrom)
; "from" 在 LogEntities 外部,翻译器无法对其值以及如何计算记录进行任何假设。因此,很可能您只是将完整的 LogEntities 下载到客户端并将其过滤到客户端。如果记录数很大,你会得到超时错误。
在第二个查询中,您加入了简单表达式 Where(x => x.DomainUserLogin == uid);
,该表达式清楚地翻译为 sql。因此,您得到了正确的 sql 查询,该查询在 sql 服务器端过滤了大多数记录。
您可以使用 SQL 探查器或 VS 工具(取决于 VS 版本,或启用在 EF 中登录以查看执行的实际查询。