【发布时间】:2019-06-09 10:08:27
【问题描述】:
我们安装了一个使用英语(美国)语言的 SQL Server 2008R2 实例。 SSMS > 实例 > 属性 > 常规。
我们使用默认语言“英式英语”设置了登录。 SSMS > 安全 > 登录 > 用户 > 属性。
前端 .NET Core 应用程序通过表单/Web API 生成插入语句 (EF),它使用上面设置的登录创建“sp_executesql”系统存储过程。
使用 SQL Server Profiler,我可以看到生成的插入 SQL 包含'yyyy-mm-dd'. 格式的字符串日期,例如"2019-01-15 10:59:19.410"。
在执行该语句之前,有一个 exec sp_reset_connection 后跟以下 SET 语句(我相信这与连接池共享有关,以确保每次登录都正确设置)。
-- network protocol: LPC
set quoted_identifier on
set arithabort off
set numeric_roundabort off
set ansi_warnings on
set ansi_padding on
set ansi_nulls on
set concat_null_yields_null on
set cursor_close_on_commit off
set implicit_transactions off
set language British
set dateformat dmy
set datefirst 1
set transaction isolation level read committed
令我困惑的是,即使有yyyy-mm-dd 格式的日期,而环境设置为英式英语 (DMY),该语句也能成功运行。例如 - "2019-01-15 10:59:19.410"。
我了解到,如果 DMY 是当前设置,“2019-01-15 10:59:19.410”将被解释为 2019 年第 15 个月的第一天。
例如这将失败,因为 SQL 将尝试将日期字符串解释为 yyyy-dd-mm
SET LANGUAGE [British English];
SELECT
CAST('2019-01-13' AS DATETIME);
Msg 242, Level 16, State 3, Line 3 varchar 数据的转换 type 到 datetime 数据类型导致超出范围的值。
将语言设置为英语 (us_english) 将字符串解释更改为 MDY 并且上述语句有效。
我知道我可以使用明确的日期字符串,但我遇到的问题与 EF 前端生成的日期字符串有关。
我无法弄清楚为什么该语句运行成功。显然存在从日期字符串到 DATETIME 类型的隐式转换。
如果我从 SQL 探查器复制语句并粘贴到 SSMS 并尝试针对同一个数据库/同一个用户运行,那么它会像我预期的那样失败。
消息 8114,级别 16,状态 1,第 14 行错误转换数据类型 varchar 到日期时间。
所以...
我了解从字符串日期转换为 DATETIME 类型并在 SSMS 中运行查询获得一致的结果时发生了什么,但我不明白为什么在 SSMS 中失败的查询是从前端运行的。
如果没有很好地解释,我深表歉意。
【问题讨论】:
-
个人建议使用 ISO 格式;那么无论语言设置如何,您都不会遇到问题。因此,对于日期,使用
yyyyMMdd(即'20190115'),对于日期时间使用yyyy-MM-ddThh:mm:ss.ssssss(即'2019-01-05T11:46:17.0000000')。 -
谢谢拉努。我同意你的说法,并且总是使用明确的日期字符串,但问题是我无法控制它,因为字符串是由实体框架生成的
yyyy-mm-dd -
Profiler 在骗你。当执行采用
DATETIME类型参数的存储过程/准备语句时,它将以不保证以独立于语言的方式工作的方式格式化参数值,但客户端代码将DATETIME值作为独立于任何格式的类型值传递,而不是传递给sp_executesql的字符串文字。这应该被认为是 Profiler 中的一个错误,因为它可以使用 few safe formats 之一。 -
例如
2019-01-15T10:59:19.410与2019-01-15 10:59:19.410不同。在 DMY 环境(英国)中,第二种格式失败,因为 15 是第 15 个月的 SQL 事物。它在美国(us_english)MDY 环境中确实有效。问题是我很困惑为什么 EF 似乎以2019-01-15 10:59:19.410格式生成日期并在从前端运行时在 DMY 环境中成功执行,但从探查器复制的相同 SQL 不会运行(如预期的那样)。跨度> -
Jeroen - 这是有道理的。我已经开始考虑 Profiler 可能没有向我显示执行的确切 SQL 语句,并且可能正在格式化日期字符串以用于显示目的。本质上,分析器可能正在执行类似
SELECT CONVERT(VARCHAR, @SomeDate, 21)的操作来显示语句。
标签: sql-server asp.net-core entity-framework-core