背景

最近一直忙于手上澳洲线上项目的整体迁移和升级的准备工作,导致博客和公众号停更。本周终于艰难的完成了任务,借此机会,总结一下项目中遇到的一些问题。

EF Core 一直是我们团队中中小型项目常用的 ORM 框架,在使用 SQL Server 作为持久化仓储的场景一下,一直表现还中规中矩。但是在本次项目中,项目使用了 MySql 作为持久化仓储。为了与 EF Core 集成,团队使用了Pomelo.EntityFrameworkCore.MySql作为 EF Core For MySql 的扩展。在开发过程中,团队遇到了各种各样在 SQL Server 场景下没有遇到过的问题,其中最奇怪的,也是隐藏最深的问题,就是将DateTime.Now作为查询条件,产生了非预期的结果。

问题场景

本周在项目升级的过程中,客户反馈了一个问题。

在当前系统的 Dashboard 页面,有一个消息提醒功能,客户可以自定义一些消息,并且指定提醒的日期。客户遇到的问题是通常添加的消息提醒,在指定日期的上午时间段是不会显示,只有在下午时间段才能看到,比如说客户指定 2019 年 10 月 26 号看到一个的消息提醒,但是在 10 月 26 日这天早上 8:00-12:00 这个时间段,系统总是看不到提醒,只有到了下午的时间段才能看到提醒。

PS:这里客户表达的只是个笼统的问题,但问题确实是上午的大部分时间是看不到消息提醒的,但并不是精确到中午 12:00 点这个时间, 所以此处不必过于纠结于具体的时间。

查看问题代码

看到这个问题的时候,我自己也很奇怪,难道代码或者数据库使用了时区,导致查询出现了偏差?

于是我就 Review 了一下此处的查询, 代码如下。

var query = DbContext.CRM_Note_Reminders    .Include(x => x.CRM_Note)    .Where(x => !x.CRM_Note.Is_Deleted             && !x.Is_Deleted             && x.Reminder_Date.Date               <= DateTime.Now.Date)     .ToList();

PS: 这里可能有同学会有疑问,为啥不用DbFunctions.DiffDays? 原因是DbFunctions.DiffDays是 EF Core for SQLServer 的扩展方法,针对 MySql 还没有官方的实现方案。

从这个查询中,我没有看出任何问题,于是我直接借助一些日志工具,将 EF Core 生成的查询语句的输出了出来。

其中 WHERE 条件部分如下:

WHERE (((`x.CRM_Note`.`Is_Deleted` = FALSE)AND (`x`.`Is_Deleted` = FALSE))AND (CONVERT(`x`.`Reminder_Date`, date)  <= CONVERT(CURRENT_TIMESTAMP(), date)))

这里CURRENT_TIMESTAMP()是 MySql 的内置函数,与 SQLServer 的内置函数GETDATE()不同,CURRENT_TIMESTAMP()默认返回的是 UTC 时间。因此我们大概能知道,为什么澳洲客户会遇到上面的场景了。

由于澳洲处于东 10 区,与 UTC 时间有+10 个小时的时差,所以当澳洲上午的 10 点之前,UTC 时间都是在当前澳洲日期的前一天,所以系统中出现了当天的消息提醒在上午时间段不能正常显示的问题。

PS:由于澳洲是分冬令时和夏令时的,夏令时时间要加一个小时,所以实际上客户在每天的 11 点之前都无法看到正确的消息提醒。

深入思考

你这可能会非常奇怪,为什么DateTime.Now会被转化成内置函数CURRENT_TIMESTAMP(),而没有使用我们传入的值DateTime.Now.Date呢?

其实 EF/EF Core 在查询是时候是分 2 个阶段的,一个是组合查询表达式树的阶段,一个是真正的查询阶段。

在组合查询表达式树的阶段,EF/EF Core 只会去组合表达式,而不会去尝试计算表达式的值,所以这个阶段DateTime.Now.Date的值并没有被计算出来, 在进入正常查询阶段的时候, EF/EF Core 会尝试将查询表达式树翻译成 SQL 脚本,这时候由于我们的EF ProviderMySql Provider, 恰巧DateTime.Now可以翻译成 Mysql 的内置函数CURRENT_TIMESTAMP(), 所以这里 EF/EF Core 就跳过了表达式值的计算,直接将其翻译成了对应的内置函数,所以导致生成的 SQL 查询和我们的预期有偏差。

那么我们该如何解决这个问题呢?

解决方案

经过了以上的思考,其实解决这个问题也就很简单了,我们可以将DateTime.Now.Date先计算出来,保存在一个变量中,然后将这个变量传入查询中。

var today = DateTime.Now.Date;

var query = DbContext.CRM_Note_Reminders     .Include(x => x.CRM_Note)     .Where(x => !x.CRM_Note.Is_Deleted             && !x.Is_Deleted             && x.Reminder_Date.Date <= today)     .ToList();

由此生成的 MySQL 脚本如下:

WHERE (((`x.CRM_Note`.`Is_Deleted` = FALSE)AND (`x`.`Is_Deleted` = FALSE))AND (CONVERT(`x`.`Reminder_Date`, date) <= @__date_0))

这样我们就得到了一个正确的结果,澳洲客户也就收到了正确的消息。

是不是有种差之毫厘,谬以千里的感觉呢?

EF Core For MySql查询中使用DateTime.Now作为查询条件的一个小问题相关推荐

  1. 0配置EF连接MySql数据库_第八节:EF Core连接MySql数据库

    一. 前提 1.安装EF Core连接MySQL的驱动,这里有两类: (1).Oracle官方出品:MySql.Data.EntityFrameworkCore (版本:8.0.17) (2).其他第 ...

  2. 记一次EF Core连接MySql、Oracle

    点击上方"Dotnet9"添加关注哦 上上个月写的一篇文章,今天有同事问我使用EF Core连接MySql和Oracel的问题,我把这篇文章直接甩给了他. 下面是正文: 这几天研究 ...

  3. oracle模糊查询中的regexp_like嵌套子查询用法

    oracle模糊查询中的regexp_like嵌套子查询用法 regexp_like一般用于模糊查询某一列时包含多个查询条件 需求1:在用户表中查询出账号包含650000和230000的用户. sel ...

  4. mysql子查询重复利用_mysql – 如何在查询中多次使用子查询的结果

    MySQL查询需要不同位置的子查询结果,如下所示: SELECT COUNT(*),(SELECT hash FROM sets WHERE ID=1) FROM sets WHERE hash=(S ...

  5. sql 根据日期模糊查询SQL Server dateTime类型 模糊查询

    曾经遇到这样的情况,在数据库的Meeting表中有PublishTime (DateTime,8)字段,用来存储一个开会时间,在存入时由于要指明开会具体时间,故格式为yyyy-mm-dd hh:mm: ...

  6. access在sql中横向求和_如何在Access查询中增加总和、平均查询列

    Access的查询对象的操作,是个头痛的问题.尤其是高中信息技术考试中的查询对象的操作,如果涉及到在查询中增加求和或求平均的查询列,那么,可以算是一道难题了. 下面,本文,就给大家总结一下关于这道题, ...

  7. MySQL数据库中如何使用rand随机查询记录

    以下的文章主要介绍的是MySQL使用rand 随机查询记录效率测试,我们大家一直都以为MySQL数据库随机查询的几条数据,就用以下的东东,其实其实际效率是十分低的,以下就是文章的主要内容. 1.SEL ...

  8. 创建一个MySQL数据库中的datetime类型

    瀚高数据库 目录 环境 文档用途 详细信息 环境 系统平台:Microsoft Windows (64-bit) 10 版本:4.5 文档用途 介绍瀚高数据库中创建一个datetime类型的方法以及c ...

  9. ef core select选择实体中的部分数据

    public User {public string Name { get; set; }public string Age { get; set; }public string Color { ge ...

最新文章

  1. CSDN Markdown编辑器编辑教程
  2. document.readyState 属性
  3. NTP授时系统(GPS时钟产品-GPS授时产品)
  4. SLAM_轨迹算法精度评价指标(ATE、RPE)
  5. scara机器人dh参数表_机器人之DH参数例子-SCARA机器人
  6. WebView加载网页不显示图片解决办法
  7. 区块链开发团队,公链开发才是主战场
  8. 基于深度学习的以图搜图
  9. 自制网站服务器主机,自制服务器主机迷你
  10. Windows Defender怎么添加排除项?
  11. 山海演武传·黄道·第一卷 雏龙惊蛰 第二十五 ~ 二十六章 赤龙与紫龙
  12. 收货地址表结构 以及创建修改流程
  13. 2020年 交通领域SCI期刊分区
  14. HTTP VS HTTPS
  15. html流程svg动画,12款基于SVG的HTML5应用和动画
  16. 安装VMware Workstation 16.1
  17. 【weblogic】WTC配置(Weblogic Tuxedo Connector)
  18. 【Go语言入门100题】022 奇偶分家 (10 分) Go语言 | Golang
  19. python PDF文档
  20. 计算两个时间段之间相隔多少天

热门文章

  1. 三阶魔方魔方公式_观看此魔方的自我解决
  2. 在Windows 7或Vista(或Windows 8.x,Sorta)上禁用Aero
  3. api游戏编程鼠标选择拖动_如何选择合适的游戏鼠标
  4. 【数据库中间件】MyCat分表分库规则实现
  5. 远程连接mysql速度慢的解决方法
  6. Centos Missing Library: QtWebKit.so.4
  7. pb 动态改变DW的WHERE子句
  8. eclipse默认编码为GBK,修改为UTF8的方法
  9. 复制Oracle表的结构
  10. ID,ClientID,UniqueID的区别