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

C# LINQ to Entities条件给出了奇怪的结果,c#,sql,entity-framework,linq,linq-to-entities,C#,Sql,Entity Framework,Linq,Linq To Entities,尝试在LINQ查询中实现条件(使用Entityframework)会创建奇怪的查询。在某些情况下,这些查询超时,即使阈值设置为180秒: List<LogEntity> dataList = db.LogEntities.Where(x => x.Source == "Source" && (String.IsNullOrEmpty(from) || x.EventD

尝试在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>();

有没有合理的解释来解释为什么这些内联条件执行得如此糟糕

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

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

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

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

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


当前的EF查询翻译器不会减少常量表达式。不要浪费您的时间,
if
样式是正确的选择。我改变了主意。您的问题(以及其他一些问题)让我开始考虑一个通用的解决方案。您可以看看我的答案,看看自定义扩展方法是否适合您。谢谢您的解释,但是,我假设在传递给查询转换器之前要对C#语句进行评估。显然,它们不是,所以我不会这样使用它们。
                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)