小编典典

LINQ to Entities条件给出奇怪的结果

sql

试图在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)

关于这些内联条件为何表现如此差的情况,是否有合理的解释?


阅读 190

收藏
2021-04-28

共1个答案

小编典典

当您在EF数据库上使用LINQ编写查询时,它们看起来很自然,但是在后台,有一个查询转换器将LINQ查询解析并将其分为两部分:一个在sql服务器上执行,另一个在客户端上仅使用LINQ扩展名执行。

当您使用某些查询翻译器无法转换为SQL的表达式(例如某些.NET函数)时,它将最大限度地减少数据过滤,并且最终可能会将整个数据表下载到客户端并对其进行过滤。

在您写的第一个查询中,您使用(String.IsNullOrEmpty(from) || x.EventDate >=cFrom);“来自”是LogEntities的外部元素,翻译器无法对其值以及如何根据记录进行计算不做任何假设。因此,最有可能的是,您只需将完整的LogEntities下载到客户端,然后将其过滤到客户端。如果记录数量巨大,您将收到超时错误。

在第二个查询中,您加入了简单的表达式Where(x => x.DomainUserLogin ==uid);,这些表达式已明确翻译为sql。因此,您将获得正确的sql查询,该查询可以过滤sql服务器端的大多数记录。

您可以使用SQL事件探查器或VS工具(取决于VS版本,或启用EF中的日志记录来查看已执行的实际查询)。

有关MSDN的一些信息

2021-04-28