【问题标题】:Linq query with DateTime Comparison is not working as expected具有日期时间比较的 Linq 查询未按预期工作
【发布时间】:2020-07-29 20:38:37
【问题描述】:

这里的查询没有按预期工作:

var source     = from conv in AuthRepository.Database.Conversations
                 from msg in AuthRepository.Database.ConversationMessages
                 let pId = playerId
                 let lastReadDate =
                 (
                     from rd in AuthRepository.Database.ConversationReadDates
                     where rd.player_id == pId && rd.conversation_id == conv.id
                     select rd.last_read_date
                 ).FirstOrDefault()
                 // retrieve last message
                 where msg.id ==
                 (
                     from msgs in AuthRepository.Database.ConversationMessages
                     where msgs.conversation_id == conv.id
                     orderby msgs.created descending
                     select msgs.id
                 ).FirstOrDefault()
                 // check if last message was read by player
                 where msg.created > lastReadDate
                 select conv.id;

return await source.CountAsync();

在我的测试中,“lastReadDate”应该是 DateTime 的默认值,因为没有找到 last_read_date。 但是这个 where 子句失败了:where msg.created > lastReadDate 我已经检查过 msg.created 的值是否正确。

但是当我通过首先检索 lastReadDate 部分然后在第二个查询中使用它来将查询分成两部分时,它可以按预期工作,如下所示:

var sourceReaddate = from rd in AuthRepository.Database.ConversationReadDates
                                 from conv in AuthRepository.Database.Conversations
                                 where rd.player_id == playerId && rd.conversation_id == conv.id
                                 select rd.last_read_date;
var readDate = await sourceReaddate.FirstOrDefaultAsync();

var source = from conv in AuthRepository.Database.Conversations
             from msg in AuthRepository.Database.ConversationMessages
             let pId = playerId
             let lastReadDate = readDate
             // check if player is authorized to see the conversation
             where !pId.HasValue ||
             (
                from auth in AuthRepository.Database.ConversationAuthorization
                let conversation = auth.conversation
                where conversation.id == conv.id && auth.player_id == pId.Value
                select conversation.id
             ).Any()
             // retrieve last message
             where msg.id ==
             (
                from msgs in AuthRepository.Database.ConversationMessages
                where msgs.conversation_id == conv.id
                orderby msgs.created descending
                select msgs.id
             ).FirstOrDefault()
             // check if last message was read by player
             where msg.created > lastReadDate
             where !conv.deleted
             select conv.id;
             
return await source.CountAsync();

我怀疑这是 EF Core 中的一个错误(我使用的是 3.1.6 版本)可能与 issue 相关? 但也许这是我这边的一个错误。你知道问题出在哪里吗?

这个查询还有一个非常令人不安的结果:

var source  = from conv in AuthRepository.Database.Conversations
              from msg in AuthRepository.Database.ConversationMessages
              let pId = playerId
              let lastReadDate =
              (
                 from rd in AuthRepository.Database.ConversationReadDates
                 where rd.player_id == pId && rd.conversation_id == conv.id
                 select rd.last_read_date
              ).FirstOrDefault()
              // retrieve last message
              where msg.id ==
              (
                 from msgs in AuthRepository.Database.ConversationMessages
                 where msgs.conversation_id == conv.id
                 orderby msgs.created descending
                 select msgs.id
              ).FirstOrDefault()
              select new 
              { 
                  msgCreated = msg.created,
                  lastReadDate, 
                  read = msg.created <= lastReadDate, 
                  unread = msg.created > lastReadDate,
                  sup = msg.created > default(DateTime),
                  defEqual = lastReadDate.Equals(default(DateTime)),
                  defSup = lastReadDate > default(DateTime),
                  defInf = lastReadDate < default(DateTime),
              };
              
var result = await source.ToListAsync();

这里是上面查询的结果:

{ 
    msgCreated = {07/29/2020 10:48:14}, 
    lastReadDate = {01/01/0001 00:00:00}, 
    read = false, 
    unread = false, 
    sup = true, 
    defEqual = false, 
    defSup = false, 
    defInf = false 
}

“已读”和“未读”都被评估为假是不正常的。知道为什么吗?

【问题讨论】:

  • 首先,对照 Linq 查询检查生成的 SQL。 EF Core 在information 级别记录查询。

标签: asp.net-core linq-to-sql entity-framework-core


【解决方案1】:

感谢post

var source     = from conv in AuthRepository.Database.Conversations
                 from msg in AuthRepository.Database.ConversationMessages
                 let pId = playerId
                 let lastReadDate =
                 (
                     from rd in AuthRepository.Database.ConversationReadDates
                     where rd.player_id == pId && rd.conversation_id == conv.id
                     select (DateTime?)rd.last_read_date
                 ).FirstOrDefault() ?? default(DateTime)
                 // retrieve last message
                 where msg.id ==
                 (
                     from msgs in AuthRepository.Database.ConversationMessages
                     where msgs.conversation_id == conv.id
                     orderby msgs.created descending
                     select msgs.id
                 ).FirstOrDefault()
                 // check if last message was read by player
                 where msg.created > lastReadDate
                 select conv.id;

return await source.CountAsync();

【讨论】:

    猜你喜欢
    • 2020-03-04
    • 1970-01-01
    • 2019-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多