将 ADO.NET 传递给存储过程时如何指定日期格式?

How to specify date format used by ADO.NET when passing it to a stored procedure?

我正在使用 ADO.NET 将日期时间参数传递给存储过程,我得到

Error converting data type varchar to datetime

在配置了 DATEFORMAT ydm 的服务器上。

我有一个简单的存储过程(它只接受一个参数,什么都不做):

CREATE PROCEDURE [dbo].[TestDate]
    @date AS datetime
AS
BEGIN
    RETURN 0
END

我正在 ADO.NET 通过使用 datetime 参数执行它:

Dim param As SqlParameter = New SqlParameter()
param.SqlDbType = SqlDbType.DateTime
param.Value = New Date(2021, 1, 13)

SQL 端的执行如下所示:

EXEC sp_executesql N'EXEC dbo.TestDate @date = @date', N'@date datetime', @date = '2021-01-13 00:00:00.000'

它适用于我们的大多数服务器。不幸的是,我们的一位客户有不同的配置。我通过在之前的执行中添加 SET DATEFORMAT ymd 来模拟这个,所以当它运行时它会抛出

Error converting data type varchar to datetime

SET DATEFORMAT ydm;

EXEC sp_executesql N'EXEC dbo.TestDate @date = @date', N'@date datetime', @date = '2021-01-13 00:00:00.000'

似乎 ADO.NET 以对日期格式/语言设置敏感的 ODBC 格式传递日期。你知道如何克服这个问题吗? (我试过将日期作为 ISO 8601 格式的字符串传递,它适用于这个示例,但我们的一些其他查询有其他问题,我不喜欢这种“肮脏的技巧”)。

编辑:

感谢回复,我已经再次检查了sp代码。我进一步简化了示例:我已经在客户端服务器上使用分析器捕获了实际过程的执行情况,并且删除了所有“噪声代码”。在客户端环境中(来自应用程序和 Management Studio)我得到

Error converting data type varchar to datetime

(可以通过设置日期格式来模拟:SET DATEFORMAT dmy - 我已经从 DBCC USEROPTIONS 中检查过了):

exec sp_executesql N'',N'@date datetime',@date='2021-01-27 10:04:55.263'

日期没有格式,它们是二进制值。在 .NET 中 DateTime 在内部使用滴答计数字段。 SQL 服务器使用多种日期类型,none 其中基于、解析或存储为字符串。 ADO.NET 将参数作为单独的二进制参数传递给对服务器的 RPC 调用。

丢失的数据访问代码的一种或另一种方式是将日期转换为字符串而不是使用参数化查询。

此代码不会将日期转换为字符串,也不需要在服务器上进行解析:

Using con As SqlConnection = New SqlConnection(connectionString)
Using cmd As New SqlCommand("TestDate", con)
cmd.CommandType = CommandType.StoredProcedure

cmd.Parameters.Add("@date", SqlDbType.Date).Value = New Date(2021, 1, 13)

cmd.ExecuteNonQuery()

类型可以是任何日期类型,例如:SqlDbType.DateTimeSqlDbType.DateTime2SqlDbType.DateTimeOffset。与存储过程参数最匹配的类型是 Date

SSMS 呢?

在 SSMS 中,查询被写成 text。甚至最后的参数声明也使用文本。您需要提供正确的日期文字以避免本地化问题。

datetime 是受 DATEFORMAT 影响的遗留类型,除非使用完整的 ISO8601 字符串或未分隔的 YYYYMMDD 字符串。这意味着 YYYY-MM-DD 可以解析为 YYYY-DD-MM if datetime is used.

较新的型号没有这个问题。 date,此参数的正确类型和 datetime2datetimeoffset 都可以识别 YYYY-MM-DD,无论 DATEFORMAT 是什么。