Linq-to-SQL 和 DateTime 的怪异

Posted

技术标签:

【中文标题】Linq-to-SQL 和 DateTime 的怪异【英文标题】:Linq-to-SQL and DateTime weirdness 【发布时间】:2011-12-22 01:39:54 【问题描述】:

我们在这里对Linq-to-SQL 有非常奇怪和不一致的行为。

我们的应用程序安装在很多客户的站点上,并且在大多数情况下运行良好。 Linq-to-SQL 中的一个查询更新了一个表并将DateTime 列设置为一个新值。

在所有情况下(包括我们的开发和测试系统),这条 Linq-to-SQL 语句都会被翻译成以下内容:

UPDATE dbo.OurTable 
SET WorkTimeStamp = @WTS 
WHERE ID = @ID

@WTS = '2011-11-04 14:15:25', @ID = 555

但是,在一个客户的网站上,由于我们(目前)尚不清楚的原因,此更新被翻译成:

UPDATE dbo.OurTable 
SET WorkTimeStamp = @WTS 
WHERE ID = @ID

@WTS = 'Nov  4 2011 02:15:25PM', @ID = 555

然后由于某种原因在SQL Server 2005 上失败。

现在,该客户的服务器(Web 服务器和 SQL Server)安装了美国英语版本的 Windows Server 2008; SQL Server 中的语言设置为us_english,日期格式设置为mdy,运行更新的用户帐户在SQL Server 中的语言设置为English .....并且设置相同其他地方(例如,在我们的测试服务器基础架构上)。

所以我的问题真的是:

    到底为什么 Linq-to-SQL 会突然创建一个完全不同的相同DateTime 的表示来发送到 SQL Server?有没有旋钮可以控制这个?

    为什么 ADO.NET 和 SQL Server 2005 SP2 数据库不能正确处理 UPDATE 语句?我们的日志中出现错误,内容如下:

SqlTypeException - SqlDateTime 溢出。必须在 1753 年 1 月 1 日凌晨 12:00:00 到 9999 年 12 月 31 日晚上 11:59:59 之间。

这似乎是一个 .NET 错误(不仅仅是 SQL Server 错误),而且似乎 .NET 由于某种原因无法真正将 Nov 4 2011 02:15:25PM 解释为有效的 DateTime。当尝试在 SQL Server Management Studio 中运行生成的 UPDATE 语句时,我们似乎无法“强制”该错误发生 - UPDATE 可以正常工作.....

更新:一些进一步的调查似乎表明 Linq-to-SQL 在针对 SQL Server 2005 或 2008 时的行为有所不同。

使用 SQL Server 2005,我们的日期变成:Nov 4 2011 02:15:25PM 使用 SQL Server 2008,我们的日期变成:2011-11-04 02:15:25PM

【问题讨论】:

请检查 C#/VB.NET 应用程序的 CurrentCulture 设置。 @BogdanSahlean:CurrentCulture 在所有系统上都设置为 InvariantCulture 我同意这是一个 .NET 问题,而不是 SQL。可能是 LINQ2SQL 中的一个错误,忘记在某处使用不变文化。 Windows 位置设置是否匹配? 另外:这是一个网络应用吗?尝试在 web.config 中明确设置文化。 我是否正确理解语句UPDATE dbo.OurTable SET WorkTimeStamp = @WTS WHERE ID = @ID @WTS = 'Nov 4 2011 02:15:25PM', @ID = 555 在SQL 服务器上直接执行时不会失败?所以这个错误是本地化到 LINQ 的? 【参考方案1】:

我想你可能追错了问题。

我会先检查:

    您的LINQ to SQL 架构/数据库模型是准确的。 您的问题逻辑确保新的 DateTime 值不会超出范围。特别要检查它不能是DateTime.MinValueDateTime.MaxValue。 您没有在应用程序中执行任何字符串到日期解析。 SQL Server 没有任何触发器(尤其是 触发器,它可能正在修改更新语句)。

我猜您(或您的客户)从获取“SqlTypeException - SqlDateTime 溢出”开始。必须介于 1/1/1753 12:00:00 AM 和 12/31/9999 11:59:59 PM 之间”错误消息,在调查后您注意到日期显示方式的差异。

你没有提到信息来自哪里,所以我假设像 SQL 分析器这样的东西。

但是,日期显示问题可能是个红鲱鱼,因为它不应该是一个问题。

使用 SQL Server 2005,我们的日期变为:2011 年 11 月 4 日 02:15:25PM

使用 SQL Server 2008,我们的日期变成:2011-11-04 02:15:25PM

我不确定你的意思。 SQL 不会将日期'turn'转换为字符串,因为它不会将日期存储为字符串,但内部表示是一个数字(类似于自 1900 年 1 月 1 日以来的天数)。

如果您的意思是您的日期显示为 2011 年 11 月 4 日 02:15:25PM,那么这取决于显示信息的程序。

另外,据我了解,如果您使用的是 DateTime 参数(如果数据库模型准确,则 LINQ to SQL 应该这样做),那么从客户端发送到 SQL Server 的信息是 SQL 数字日期时间的表示。这应该避免客户端和服务器之间的任何日期时间转换问题。例如,当您查看 SQL Profiler 时,它不会向您显示日期的数字表示,这对大多数人来说意义不大,但会尽力提供帮助并将值显示为字符串。

重要的一点是,如果 SQL 或 SQL 分析器设法将日期时间参数显示为“2011 年 11 月 4 日 02:15:25PM”,那么它就知道这是一个有效的日期,并且它确切地知道那是什么日期。

所以我怀疑显示格式问题可能无关紧要。

这就留下了一个问题,即您的客户为什么会收到 SqlTypeException - SqlDateTime 溢出错误消息。

首先要做的是检查您设置的日期值,这需要在应用程序级别完成,而不是在 SQL Server 服务器,因为它不会达到那么远。 (这是我认为这不是 SQL 配置问题的另一个原因。)

由于某种原因,.NET 似乎无法真正将 2011 年 11 月 4 日 02:15:25PM 解释为有效的 DateTime

我看不出.NET 会在哪里尝试 将字符串解释为日期,除非你有一些DateTime.Parse 命令,如果是这样的话,那么问题就无关紧要了使用 LINQ 或 SQL。

【讨论】:

(2) DateTime 设置为 DateTime.Now.AddMinutes(5) 这样的东西,所以我很确定它不是“超出范围” 他是说 .NET 将日期转换为字符串表示形式以用于更新查询,而不是 SQL 将其转换为字符串。而且,与 2008 年相比,.NET 为 SQL 2005 发布了不同格式的日期字符串,并且 SQL 2005 不理解查询,因为它似乎无法理解该格式。 @marc_s 我知道这不太可能,但是 DateTime.Now 是否有可能超出范围,即计算机/服务器日期错误? @MystereMan 但是.NET(或者更确切地说是Linq2Sql)不应该,根据我的经验,不应该将日期转换为更新语句的字符串。我可以看到发生字符串到日期转换的唯一方法是,如果 dotnet 类变量被定义为一个字符串,这意味着架构/模型是错误的。 @sgmoore:看起来确实如此——至少我们在 SQL Server Profiler 日志中看到的是这样的;该语句使用参数(@p1@p2 等)发送到 SQL Server,并且该参数的 value 似乎作为日期的字符串表示形式发送 - 一次以一种格式,一次又一次....

以上是关于Linq-to-SQL 和 DateTime 的怪异的主要内容,如果未能解决你的问题,请参考以下文章

EF 6.x,LINQ-to-SQL和原始SQL子句

WCF、Linq-to-SQL 和参数化构造函数

Linq-to-Sql:递归获取孩子

Linq-to-SQL 数据库文件为空

一个关于A标签和分页的怪问题!

T-SQL IsNumeric()和Linq-to-SQL