LINQ to Entitys条件语句给出了奇怪的结果

本文关键字:结果 to Entitys 条件 语句 LINQ | 更新日期: 2024-10-24 06:31:01

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

为什么这些内联条件语句表现如此糟糕,有什么合理的解释吗?

LINQ to Entitys条件语句给出了奇怪的结果

当您在EF数据库上使用LINQ编写查询时,它们看起来非常自然,但在后台,有一个查询翻译器可以解析您的LINQ查询,并将其分为两部分:一部分在sql server上执行,另一部分在客户端上仅使用LINQ扩展。

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

在您编写的第一个查询中,您使用(String.IsNullOrEmpty(from) || x.EventDate >= cFrom);"from"在LogEntities之外,翻译器无法对其值以及如何根据记录计算进行任何假设。因此,最有可能的是,您只需将完整的LogEntities下载到客户端并将其过滤到客户端。如果记录数量很大,则会出现超时错误。

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

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

MSDN 上有一些信息