Linq查询和日期格式的问题

4

我是一名使用Visual Studio 2008编写C#控制台应用程序的开发者。

我的系统文化是en-GB。我有一个类似于以下代码的Linq查询:

var myDate = "19-May-2010";

var cus = from x in _dataContext.testTable
     where x.CreateDate == Convert.ToDateTime(myDate)
     select x;

生成的SQL查询会出现错误,因为日期被返回为"19/05/2010",而系统将其解释为不正确的日期。尽管我的系统文化设置为en-GB,但由于某种原因它似乎正在尝试将其解释为en-US日期。
有什么办法可以解决这个问题吗?
编辑:感谢评论中提到的魔术字符串和变量滥用,但这不是我的问题。我的问题是在从Linq转换为SQL时,日期被解释为美国格式的日期(19/05/2010被解释为:月份十九,日五,年份2010),从而导致以下错误:
System.Data.SqlClient.SqlException: The conversion of a char data type to a datetime data type resulted in an out-of-range datetime value

生成的SQL查询语句中的where子句如下:
WHERE ([t0].[CreateDate] = '19/05/2010 00:00:00') 

请注意,在LinqPad中完全相同的Linq查询可以正常工作。
我尝试了以下where子句:
where x.CreateDate == DateTime.Today

并且仍然收到错误信息。

附加信息:

SQL Server 查询可视化器:

SELECT [t0].[field1], [t0].[field2], [t0].[field3] AS [field4], [t0].[field5]
FROM [dbo].[table] AS [t0]
WHERE ([t0].[CreateDateTime] = '19/05/2010 00:00:00') 

Original query:
SELECT [t0].[field1], [t0].[field2], [t0].[field3] AS [field4], [t0].[field5]
FROM [dbo].[table] AS [t0]
WHERE ([t0].[CreateDateTime] = @p0) 
-------------------------------
@p0 [DateTime]: 19/05/2010 00:00:00

LINQPad:


-- Region Parameters
DECLARE @p0 DateTime SET @p0 = '2010-05-19 00:00:00.000'
-- EndRegion
SELECT [t0].[field1], [t0].[field2], [t0].[field3] AS [field4], [t0].[field5]
FROM [table] AS [t0]
WHERE ([t0].[CreateDateTime] = @p0)

在上面的内容中,我注意到LinqPad呈现的日期格式与VS不同。谢谢。Alan T
6个回答

3
不要将本地字符串发送到数据库中,并要求数据库将这些字符串转换为DateTime。千万不要这样做。
var myDate = "19-May-2010"; 

var cus = from x in _dataContext.testTable 
  where x.CreateDate == Convert.ToDateTime(myDate) 
  select x; 
  • 不要滥用变量。
  • 将您打算在数据库中发生的操作与您打算在本地发生的操作分开。

因此...

string myInput = "19-May-2010";
DateTime myDate = Convert.ToDateTime(myInput);

IQueryable<TestTable> cus =
  from x in _dataContext.testTable
  where x.CreateDate == myDate
  select x;

针对此更新的回应。

  • 看起来你的应用程序发送的日期时间格式是正确的,但它正在使用一个期望错误格式日期时间的连接。
  • 你可以更改每个连接或更改登录默认值:http://support.microsoft.com/kb/173907

嗨,David,我尝试了你的建议,但仍然出现错误。我已经在我的问题中添加了更多信息。 - Alan T
嗨David,谢谢你提供的链接。我不想在数据库层面上设置任何东西,因为还有其他数据库在运行。至于登录默认值,我将用户的语言从英语更改为英式英语,但没有成功。关于每个连接,我不知道如何通过Linq实现这一点。我认为数据库服务器是问题所在,因为在开发和生产服务器上运行SQL版本查询时都会出现相同的错误。 - Alan T
var 使代码难以阅读。如果你从查询开始阅读,你会发现 myDate 被使用了。如果你想知道 myDate 的类型,你需要查看它的声明。声明并没有告诉你,所以现在你需要查看它的初始化。相反,第一个程序员可以把类型放进去,这样就可以省略编译器和所有未来程序员的推理步骤。 - Amy B
1
你只需将鼠标悬停在变量上,VS 就会告诉你。 - Hans

2

简短回答是“不要使用字符串来表示日期”。

假设CreateDate列是SQL Server datetime类型,您可以直接使用.NET DateTime类进行比较。


如果你确实需要将输入作为字符串并进行转换,请使用dcp的代码片段。如果你不是绝对需要使用字符串,请避免使用它。 - Bill
嗨,比尔,我最初使用了DateTime.Now.Date,遇到了同样的问题。字符串是我的第二次尝试。有趣的是,如果我将字符串放在where子句中,它就可以工作! - Alan T
很奇怪,但我猜当linq构建实际的SQL查询时,它将日期字符串输出为en-US而不是en-GB。做一个日期比较并查看输出的SQL将会很有趣。 - Bill

1

您可以使用:

x.CreateDate == DateTime.ParseExact(myDate, "dd-MMM-yyyy", System.Globalization.CultureInfo.InvariantCulture);

当然,这假定您在数据库中的日期与myDate字段匹配(即,如果您的日期包括时间,则需要修改上述内容以包括时间部分)。


嗨dcp,我尝试了你的建议,但仍然出现错误。我已经在我的问题中添加了错误详细信息。 - Alan T

0
正如Bill所说,不要使用字符串来表示日期。LINQ to SQL使用参数化查询来传递参数,因此如果您的数据库字段和参数都是日期,则不应该有任何区域设置问题。
您可以通过将TextWriter对象(例如Console.Out)附加到DataContext的Log属性来检查生成的SQL语句。以下代码:
using(var datacontext=new DatesDataContext())
{
    var myDate=DateTime.Today;
    //Or, to specify a date without string parsing
    //var myDate=new DateTime(2010,6,16);
    var dates = from date in datacontext.DateTables
        where date.DateField == myDate                 
        select date;

    datacontext.Log = Console.Out;
    foreach (var date in dates)
    {
        Console.WriteLine(date.DateField);
    }
}

生成了此查询

SELECT [t0].[DateField]
FROM [dbo].[DateTable] AS [t0]
WHERE [t0].[DateField] = @p0
-- @p0: Input DateTime (Size = -1; Prec = 0; Scale = 0) [6/16/2010 12:00:00 AM]
-- Context: SqlProvider(Sql2008) Model: AttributedMetaModel Build: 4.0.30319.1

正如您所见,查询具有DateTime类型的参数并返回正确的条目。

您遇到的错误是什么?您是否遇到异常或获得不正确的结果? 如果您没有获得任何结果,可能是因为您的数据库字段包含时间值,在这种情况下,它将无法匹配仅包含日期值的参数。


嗨,Panagiotis,我遇到了以下错误:System.Data.SqlClient.SqlException:将char数据类型转换为datetime数据类型导致超出范围的datetime值。 - Alan T
你能发布由LINQ to SQL生成的完整语句,包括提供程序的注释吗? LINQ始终使用参数化查询来传递参数。它不应该创建你已经发布的WHERE语句。 - Panagiotis Kanavos
嗨,Panagiotis,我已经在我的问题中添加了更多信息。 - Alan T

0

当您尝试此操作时会发生什么

var myDate = "20100519"; 

var cus = from x in _dataContext.testTable 
     where x.CreateDate == Convert.ToDateTime(myDate) 
     select x; 

嗨,Madhivanan,我遇到了以下错误:“System.InvalidCastException:指定的转换无效” - Alan T

0

我知道你可能已经检查过了,但你能验证以下内容吗:

  1. CreateDate 在数据库中被声明为 DateTime 或 DateTime2
  2. 你的 Linqed 类中的 CreateDate 属性被声明为 .NET 的 DateTime
  3. 在你的 Linqed up 类的 CreateDate 属性上定义了 System.Linq.Mapping.ColumnAttribute。

基于你在 LinqPad 中看到查询成功的事实,我怀疑 CreateDate 属性或该字段的 SQL 定义存在问题。我真的怀疑你的 Linq-to-SQL 输出是 "WHERE ([t0].[CreateDate] = '19/05/2010 00:00:00')" 而不是 "WHERE ([t0].[CreateDate] = @p0)"。


嗨,mattmc3,我已经在我的问题中添加了更多信息。 - Alan T

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接