2010-02-24 53 views
4

我用兩個LINQ查詢訪問使用實體框架我的數據庫:針對實體框架的LINQ查詢如何將日期傳遞給SQL Server?

第一存儲令牌在數據庫中,並賦予它60秒超時:

string tokenHash = GetTokenHash(); 
Token token = new Token() 
{ 
    Client = client, 
    Expiry = DateTime.Now.AddSeconds(60), 
    UserId = userId, 
    TokenHash = tokenHash, 
}; 
context.AddToToken(token); 
context.SaveChanges(); 

第二檢查匹配令牌尚未到期:

var item = (from t in datasource.SmsToken 
      where t.Client.Id == clientId 
      && t.UserId == userId 
      && t.TokenHash == tokenHash 
      && t.Expiry > DateTime.Now 
      select t); 
bool success = item.Count() >= 1; 

我遇到的問題是,這是在測試服務器上完美的工作。現在,它已移到不同的環境,它不再有效。

我已經傾倒了大量的調試信息,一切似乎都匹配。如果我刪除t.Expiry > DateTime.Now條件,它工作正常。所以問題在於日期比較。

新服務器已在Windows中使用不同的日期格式和全球化設置進行設置。我認爲這是問題,這讓我困惑。

我原以爲會使用LINQ和EF存儲和檢索日期。我應該沒有任何格式問題?誰能告訴我這裏有什麼問題?


更新:

有趣的是,我用替換檢索代碼得到正確的行爲如下:

var item = (from t in datasource.SmsToken 
      where t.Client.Id == clientId 
      && t.UserId == userId 
      // && t.TokenHash == tokenHash 
      // && t.Expiry > DateTime.Now 
      select t).ToList(); 

var matchingToken = (from t in item 
        where t.TokenHash == tokenHash 
        && t.Expiry > DateTime.Now 
        select t).FirstOrDefault(); 

bool success = matchingToken != null; 

這表明,我認爲這個問題是與日期比較做在Linq-to-entities之內。 Linq到對象工作正常!

+2

您可以針對兩臺服務器運行跟蹤並查看實際執行的是什麼sql? – kristian 2010-02-24 05:49:23

+0

我可以,是的...好主意。 – Damovisa 2010-02-24 05:54:43

+0

明天我必須跟進這個。感謝您的建議。 – Damovisa 2010-02-24 07:25:47

回答

1

由於克里斯蒂安的建議,我已經工作了:

此代碼:

var item = (from t in datasource.SmsToken 
      where t.Client.Id == clientId 
      && t.UserId == userId 
      && t.TokenHash == tokenHash 
      && t.Expiry > DateTime.Now 
      select t); 
bool success = item.Count() >= 1; 

呈現此SQL:

exec sp_executesql N'SELECT 
1 AS [C1], 
[Extent1].[Id] AS [Id], 
[Extent1].[UserId] AS [UserId], 
[Extent1].[TokenHash] AS [TokenHash], 
[Extent1].[Expiry] AS [Expiry], 
[Extent1].[ClientId] AS [ClientId] 
FROM [dbo].[Token] AS [Extent1] 
WHERE ([Extent1].[ClientId] = @p__linq__16) 
AND ([Extent1].[UserId] = @p__linq__17) 
AND ([Extent1].[TokenHash] = @p__linq__18) 
AND ([Extent1].[Expiry] > (GetDate()))', 
N'@p__linq__16 nvarchar(7),@p__linq__17 nvarchar(9),@p__linq__18 nvarchar(16)',@p__linq__16=N'OTPTest',@p__linq__17=N'Test User',@p__linq__18=N'7?????:??????' 

注行:AND ([Extent1].[Expiry] > (GetDate()))',

這意味着什麼是LINQ-to-Entities tra在數據庫中使用DateTime.NowGetDate()進行比較。因此,服務器之間的任何時間差異都會導致問題。

我的解決方案是保留原始查詢的日期比較,並在所有事情都回來時用LINQ到對象來完成。

2

您是否插入令牌並在具有相同時區的服務器上檢索比較?

如果您從不在數據庫中存儲本地時間,那會更好。首先,它消除了在一個時區出現排隊問題,並將其排入另一個時區。其次,代碼一年四季都可以工作:現在,您的代碼每年將在「設計」兩晚失敗:夏令時開始,夏令時結束。

更好地使用DateTime.UtcNow排隊和出隊操作。

現在有人說,這不太可能是你面臨的問題。但要知道您的案例中發生的比較類型,我們需要知道數據庫中聲明的和EF中聲明的Expiry列的類型。它是一個字符串,它是datetime還是datetimeoffset?

+0

是的,我粘貼的代碼實際上是在同一個Web服務中的兩個獨立方法的部分。這是一臺單一的服務器,因此它將始終從同一個地方運行。數據庫中的Expiry列是日期時間。 – Damovisa 2010-02-24 06:15:12

+0

對不起,日期時間在數據庫和日期時間在代碼中。 – Damovisa 2010-02-24 06:44:28

+0

難道是你查找它的時候令牌過期了嗎?您只允許60秒,直到到期,這是從創建toke的時間開始,而不是從何時開始保存。你確定你在60秒內開始查找? – 2010-02-24 06:49:22