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

背景

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

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))

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/312881.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

进程的同步与互斥

现代操作系统采用多道程序设计机制&#xff0c;多个进程可以并发执行&#xff0c;CPU在进程之间来回切换&#xff0c;共享某些资源&#xff0c;提高了资源的利用率&#xff0c;但这也使得处理并发执行的多个进程之间的冲突和相互制约关系成为了一道难题。如果对并发进程的调度不…

缓存击穿/穿透/雪崩

缓存击穿/穿透/雪崩Intro使用缓存需要了解几个缓存问题&#xff0c;缓存击穿、缓存穿透以及缓存雪崩&#xff0c;需要了解它们产生的原因以及怎么避免&#xff0c;尤其是当你打算设计自己的缓存框架的时候需要考虑如何处理这些问题。缓存击穿一般的缓存系统&#xff0c;都是按照…

99%的人不知道搜索引擎的6个技巧

点击上方“dotNET全栈开发”&#xff0c;“设为星标”加“星标★”&#xff0c;每天11.50&#xff0c;好文必达全文约900字&#xff0c;预计阅读时间1分钟今天看了一期seo优化的视频&#xff0c;其中就有这么一篇关于百度搜索的几个小技巧&#xff0c;这里整理出来&#xff0c;…

用信号量解决进程的同步与互斥

转自&#xff1a;http://www.cnblogs.com/whatbeg/p/4435286.html 现代操作系统采用多道程序设计机制&#xff0c;多个进程可以并发执行&#xff0c;CPU在进程之间来回切换&#xff0c;共享某些资源&#xff0c;提高了资源的利用率&#xff0c;但这也使得处理并发执行的多个进程…

扎心了,程序员2017到2019经历了什么?

刷爆朋友圈的2017-2019到底是什么梗&#xff1f;只剩下33天了&#xff0c;就到2020年了最后一批90后&#xff0c;马上就要30了&#xff1f;一到年底&#xff0c;就会陷入回忆和比较中近几日&#xff0c;网友开始将2017年和2019年进行对比&#xff0c;不少人晒出了自己在17年和1…

【.NETCore 3】Ids4 ║ 统一角色管理(上)

前言书接上文&#xff0c;咱们在上周&#xff0c;通过一篇《思考》 性质的文章&#xff0c;和很多小伙伴简单的讨论了下&#xff0c;如何统一同步处理角色的问题&#xff0c;众说纷纭&#xff0c;这个我一会儿会在下文详细说到&#xff0c;而且我最终也定稿方案了。所以今天咱们…

.NET Core 3.0 使用Nswag生成Api文档和客户端代码

摘要在前后端分离、Restful API盛行的年代&#xff0c;完美的接口文档&#xff0c;成了交流的纽带。在项目中引入Swagger &#xff08;也称为OpenAPI&#xff09;&#xff0c;是种不错的选择&#xff0c;它可以让接口数据可视化。下文将会演示利用Nswag如何生成Api文档利用NSwa…

深入研究 Angular 和 ASP.NET Core 3.0

本文要点&#xff1a;可以把多个 Angular 应用程序集成到 ASP.NET 网站中把 Angular 代码打包成 Web 组件是引导 Angular 应用程序的好方法可以把用 Angular 编写的 Web 组件轻松地集成到 ASP.NET 视图中把 Angular 解决方案构造成 Angular 应用程序的集合以实现更好的代码重用…

操作系统内存管理--简单、页式、段式、段页式

一、内存管理的目的和功能 内存一直是计算机系统中宝贵而又紧俏的资源&#xff0c;内存能否被有效、合理地使用&#xff0c;将直接影响到操作系统的性能。此外&#xff0c;虽然物理内存的增长现在达到了N个GB&#xff0c;但比物理内存增长还快的是程序&#xff0c;所以无论物理…

网易裁员背后,芸芸众生,相煎何急

十一月初拖家带口去了上海&#xff0c;到了著名的城隍庙参观&#xff0c;无意中看到了一个仅出现在历史书上的古老物件“西洋镜”&#xff0c;仿佛跨越百年&#xff0c;来到那个如裹脚布般冗长而乏味的古老年代&#xff0c;看到了一群有一群卑微的小民在生活的裹挟之下&#xf…

.NET Core on K8S 学习与实践系列文章索引 (更新至20191126)

更新记录&#xff1a;-- 2019-11-26 增加Docker容器日志系列文章近期在学习Kubernetes&#xff0c;基于之前做笔记的习惯&#xff0c;已经写了一部分文章&#xff0c;因此给自己立一个flag&#xff1a;完成这个《.NET Core on K8S学习实践》系列文章&#xff01;这个系列会持续…

ASP.NET Core gRPC 使用 Consul 服务注册发现

一. 前言gRPC 在当前最常见的应用就是在微服务场景中&#xff0c;所以不可避免的会有服务注册与发现问题&#xff0c;我们使用gRPC实现的服务可以使用 Consul 或者 etcd 作为服务注册与发现中心&#xff0c;本文主要介绍Consul。二. Consul 介绍Consul是一种服务网络解决方案&a…

Excel催化剂插件功能修复与更新汇总篇之十

在半年时间里&#xff0c;自己使用过程中&#xff0c;发现的一些小bug&#xff0c;更新了一下&#xff0c;也追加了一些自定义函数&#xff0c;不成系统&#xff0c;就单独放在修复与更新系列中。一、第24波-批量发送邮件并指点不同附件不同变量Excel催化剂功能第24波-批量发送…

OSI/RM 开放系统互联参考模型

开放式系统互联通信参考模型&#xff08;即&#xff1a;Open System Interconnection Reference Model&#xff0c;简称为OSI模型&#xff0c;由国际标准化组织&#xff08;ISO&#xff09;提出&#xff0c;一个试图使各种计算机在世界范围内互连为网络的标准框架。 OSI的七层体…

Http benchmarking 工具 wrk 基本使用

Http benchmarking 工具 wrk 基本使用Introwrk 是一款现代HTTP基准测试工具&#xff0c;能够在单个多核CPU上运行时产生显着负载。它将多线程设计与可扩展事件通知系统&#xff08;如epoll和kqueue&#xff09;结合在一起。官方描述&#xff1a;wrk is a modern HTTP benchmark…

TCP/IP 体系结构

TCP/IP体系结构又称为TCP/IP协议簇&#xff0c;是Transmission Control Protocol/Internet Protocol的简写&#xff0c;译为传输控制协议/因特网互联协议。 TCP/IP提供点对点的链接机制&#xff0c;将数据应该如何封装、定址、传输、路由以及在目的地如何接收&#xff0c;都加以…

黑客之道-解码Facebook的DevOps之路

内容来源&#xff1a;DevOps案例深度研究第3期 – Facebook DevOps实践研究战队&#xff08;本文只展示部分PPT及研究成果&#xff0c;更多细节请关注案例分享会&#xff0c;及本公众号。&#xff09;本案例内容贡献者&#xff1a;张楠&#xff08;Topic Leader&#xff09;、高…

IP地址与MAC地址的区别

IP地址是指互联网协议地址&#xff08;Internet Protocol Address&#xff09;&#xff0c;是IP Address的缩写。IP地址是IP协议提供的一种统一的地址格式&#xff0c;它为互联网上的每一个网络和每一台主机分配一个逻辑地址&#xff0c;以此来屏蔽物理地址的差异。 MAC地址又称…

ping命令整个过程详解

转自&#xff1a;http://wanicy.blog.51cto.com/509018/335207/ 如果你想了解ping命令的原理&#xff0c;看了这篇文章&#xff0c;你会从对网络一窍不通&#xff0c;到豁然开朗。 先看拓朴图&#xff1a; 在这里讲ping的两情况&#xff1a;一种是同一网段内&#xff0c;一种…

ping某个域名的详细过程

在前一篇文章中&#xff0c;我们已经对ping命令的整个过程做了一个详解。但是&#xff0c;前一篇文章中所涉及到的两种ping命令使用情况&#xff0c;都是ping的IP&#xff0c;在这篇文章中&#xff0c;我们将要详细讲解ping某个域名的整个过程。 一、ICMP协议 在了解ping命令之…