连接时SqlDateTime溢出。必须在1/1/1753 12:00:00 AM和12/31/9999 11:59:59 PM之间

时间:2017-03-13 15:07:26

标签: c# sql join

我有一个视图(vw_users)和一个表(CTUsers)。当我从视图中请求数据时,我的sql查询曾经工作过:

var result = (from i in dc.vw_Users
              where i.CTid == ctid 
              select new 
              { 
                  UserId = i.UserId,  
                  WelcomeSent = (i.WelcomeSent != null && i.WelcomeSent.ToString().Length > 0 
                                ? DateTime.Parse(i.WelcomeSent.ToString()) 
                                 : new DateTime())
              });

但是现在我想从表中获取WelcomeSent,所以我使用这段代码:

var result = (from i in dc.vw_Users 
              join k in dc.CTUsers 
              on i.CTid equals k.CTid 
              where i.CTid == ctid 
              select new 
              { 
                  UserId = i.UserId, 
                  WelcomeSent = (k.WelcomeSent != null && k.WelcomeSent.ToString().Length > 0 
                                 ? DateTime.Parse(k.WelcomeSent.ToString()) 
                                 : new DateTime()) 
              }).Distinct();

但现在当我运行此查询时,我得到了这个错误:

  

SqlDateTime溢出。必须在1/1/1753 12:00:00 AM之间   12/31/9999 11:59:59 PM

SQL视图和表WelcomeSent类型是DateTime,它也可以是NULL。以下是WelcomeSent的示例值:2017-03-07 00:00:00.000

1 个答案:

答案 0 :(得分:0)

这里真正的问题是Distinct()方法。如果您掌握以SQL格式运行的查询并直接从SSMS运行数据库,它们将运行正常。它是LINQ to SQL,它限制了在使用Distinct()时不允许DateTime值小于某个值。

我不确定为什么你需要在datetime和字符串值之间使用奇怪的来回转换。

以下是在数据库上运行的实际查询。

第一种情况:

SELECT [t0].[Id] AS [TokenId], [t0].[Token],     
(CASE WHEN ([t0].[ExpiryDate] IS NOT NULL) 
            AND ((CONVERT(Int,LEN(CONVERT(NVarChar(MAX),[t0].[ExpiryDate])))) > @p1) 
        THEN 1        
      WHEN NOT (([t0].[ExpiryDate] IS NOT NULL) 
            AND ((CONVERT(Int,LEN(CONVERT(NVarChar(MAX),[t0].[ExpiryDate])))) > @p1)) 
        THEN 0 
      ELSE NULL     
 END) AS [value], 
 CONVERT(NVarChar(MAX),[t0].[ExpiryDate]) AS [s] 
 FROM [dbo].[TokenView] AS [t0]WHERE [t0].[Id] = @p0

第二种情况:

SELECT DISTINCT [t2].[Id] AS [TokenId], [t2].[Token], [t2].[value], [t2].[value2] AS [s], [t2].[value3]
FROM (    
    SELECT [t0].[Id], [t0].[Token], 
    (CASE WHEN ([t1].[ExpiryDate] IS NOT NULL) 
                AND ((CONVERT(Int,LEN(CONVERT(NVarChar(MAX),[t1].[ExpiryDate])))) > @p0) 
            THEN 1            
          WHEN NOT (([t1].[ExpiryDate] IS NOT NULL) 
                    AND ((CONVERT(Int,LEN(CONVERT(NVarChar(MAX),[t1].[ExpiryDate])))) > @p0))
            THEN 0            
          ELSE NULL         
    END) AS [value], 
    CONVERT(NVarChar(MAX),[t1].[ExpiryDate]) AS [value2], @p1 AS [value3]    
FROM [dbo].[TokenView] AS [t0]    
    INNER JOIN [dbo].[Tokens] AS [t1] ON [t0].[Id] = [t1].[Id]) AS [t2]
WHERE [t2].[Id] = @p2

我建议使用第二个查询的解决方案来解决问题。

使用查询创建一个可以保存您从数据库中选择的数据的类。

public class MyClass
{
    public int Id { get; set; }

    public string Token { get; set; }

    //Consider this property as WelcomeSent property from your code.
    public DateTime? ExpiryDate { get; set; }

    //Use this property only to display the data in UI.
    public DateTime FormattedExpiryDate
    {
        get
        {
            return ExpiryDate != null && ExpiryDate.ToString().Length > 0
                                        ? DateTime.Parse(ExpiryDate.ToString())
                                         : new DateTime();
        }
    }
} 

按如下方式更改查询。

var query = (from i in dc.TokenViews //TokenViews is same as vw_Users of yours.
                     join k in dc.Tokens //Tokens is same as CTUsers
                     on i.Id equals k.Id
                     where i.Id == 5 //Hardcoding the selection criteria. 
                     select new MyClass
                     {
                         Id = i.Id,
                         Token = i.Token,
                         ExpiryDate = k.ExpiryDate //Retrieving values as it is from the db.
                      }).Distinct();

显示以下值,以查看ExpiryDate和FormattedExpiryDate

之间的差异
foreach (var item in query)
{
    Console.WriteLine("Id : {0}", item.Id);
    Console.WriteLine("Token : {0}", item.Token);
    Console.WriteLine("ExpiryDate : {0}", item.ExpiryDate);
    Console.WriteLine("FormattedDate : {0}", item.FormattedExpiryDate);
}

您也可以对第一个查询使用相同的方法。这将避免SQL查询中的所有CASE WHEN子句和CONVERT