【问题标题】:EF Core Where Clause throws Exception when Comparing date with datenow将日期与 datenow 进行比较时,EF Core Where 子句抛出异常
【发布时间】:2019-10-11 19:22:57
【问题描述】:

我有一个查询方法,它应该给我从今天到 7 天的下一场比赛,给定一个联赛 ID。所以如果今天的日期是 2019 年 10 月 11 日,那么它应该给我所有的体育比赛,直到 2019 年 10 月 18 日。

        public IQueryable<MatchDTO> GetMatchesForNextSevenDaysByLeagueAsync(int leagueId)
        {
            var todayDate = DateTime.Now;
            var matches = _context.Matches.Include(e => e.HomeTeam).Include(e => e.AwayTeam).Include(e => e.League).Where(m => m.LeagueId == leagueId).OrderBy(m => m.MatchDate).ThenBy(m => m.Time).Where(m => ((todayDate - m.MatchDate).Days) <=7).Select(m => DTOConverter.ConvertMatchToDTO(m));

            return matches;
        }

调用抛出异常:

"The LINQ expression 'Where<Match>(\r\n    source: 
ThenBy<Match, DateTime>(\r\n        source: OrderBy<Match, DateTime>(\r\n            
source: Where<Match>(\r\n                source: DbSet<Match>, \r\n                
predicate: (m) => m.LeagueId == (Unhandled parameter: __leagueId_0)), \r\n            
keySelector: (m) => m.MatchDate), \r\n        keySelector: (m) => m.Time), \r\n    
predicate: (m) => m.MatchDate - (Unhandled parameter: __todayDate_1).TotalDays <= 7)' 
could not be translated. Either rewrite the query in a form that can be translated, or 
switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), 
ToList(), or ToListAsync(). 
See https://go.microsoft.com/fwlink/?linkid=2101038 for more information."

对我来说,它看起来不像我比较 .Where(m =&gt; ((todayDate - m.MatchDate).Days) &lt;=7) 中日期的方式

我曾尝试使用客户端评估,但速度太慢。关于如何重写此代码以使代码正常工作的任何想法。

请注意,我使用的是 EF Core 3.0

【问题讨论】:

  • 使用.Where(m =&gt; m.MatchDate &lt; calculatedDayWith7DaysOffset)(或&gt;)之类的东西怎么样?与常数值进行简单比较即可。
  • 不确定您所说的计算的DayWith7DaysOffset 是什么意思。我应该将它与今天的日期进行比较。你的意思是取今天的日期并给它一个 + 7 天的偏移量吗?

标签: c# .net-core ef-core-3.0


【解决方案1】:

所以这行有点难以阅读,无需来回滚动,所以我希望你不介意我为了自己的方便重新格式化了它:

var matches = _context
    .Matches
    .Include(e => e.HomeTeam)
    .Include(e => e.AwayTeam)
    .Include(e => e.League)
    .AsQueryable()
    .Where(m => m.LeagueId == leagueId)
    .OrderBy(m => m.MatchDate)
    .ThenBy(m => m.Time)
    .Where(m => ((todayDate - m.MatchDate).Days) <=7)
    .Select(m => DTOConverter.ConvertMatchToDTO(m));

通过阅读我可以看到您的第二个.Where 子句正在检查一个日期减去另一个日期的.Days 属性值。我怀疑 Entity Framework 是否能够将其转换为有效的 SQL,这就是您看到该错误的原因。

您是否有任何理由无法在客户端计算“有效”日期,然后让 SQL 根据需要过滤行?例如:

.Where(m =&gt; m.MatchDate &gt;= DateTime.Now &amp;&amp; &lt;= DateTime.Now.AddDays(7))

这应该被翻译成 TSQL BETWEEN 语句 - 这比尝试解析您存储的日期时间以获取日期部分并计算它们是否与给定日期相差一个特定数字要好得多。

也就是说,您可能想看一下您编写的一般查询。从您提供的 sn-p 中,我不太确定为什么需要 .AsQueryable - 您使用的扩展方法本身接受 IEnumerableIQueryable,因此您不必强制转换。

在您尝试对结果集进行排序之前,我还会结合两个 where 子句。不确定 EF 到 SQL 是否在所有情况下都足够聪明以优化它,但它不会受到伤害!总之,您的最终查询应如下所示:

var matches = _context
    .Matches
    .Include(e => e.HomeTeam)
    .Include(e => e.AwayTeam)
    .Include(e => e.League)
    .Where(m => 
        m.LeagueId == leagueId 
        && m.MatchDate >= DateTime.Now && <= DateTime.Now.AddDays(7))
    .OrderBy(m => m.MatchDate)
    .ThenBy(m => m.Time)
    .Select(m => DTOConverter.ConvertMatchToDTO(m));

【讨论】:

  • 是的 :D。谢了哥们。 Progman 已经在 cmets 中提到了它,所以也相信他,但我会将您的答案标记为正确。至于我复制粘贴错误的“.AsQueryable”,我在问题中进行了编辑。
  • 应该也可以使用EF.Functions.DateDiffDay(todayDate, m.MatchDate) &lt;= 7。 @HadiSalameh,你能submit an issue 吗? EF 应该只处理您的原始表达式。
  • 只是为了添加另一个数据点,我还有一个简单的 where 子句,使用 C# 时间跨度 - (t.TimeStamp - '9/23/2021 06:00 -7:00').Seconds -电话挂断了我。也不例外,挂了。我切换到 EF.Functions 方法,它正在工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-02
  • 2017-09-16
  • 1970-01-01
  • 2019-06-05
  • 1970-01-01
相关资源
最近更新 更多