[英]How do LINQ queries against the Entity Framework communicate dates to a SQL Server?
我正在使用两个LINQ查询来使用Entity Framework访问我的数据库:
第一个将令牌存储在数据库中,并为其提供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-to-objects工作得很好!
您是否插入令牌并在具有相同时区的服务器上检索比较?
如果您从不在数据库中存储本地时间,那就更好了。 首先,它消除了在一个时区中入队并出列到另一个时区的问题。 其次,代码全年都在运行:因为现在你的代码将在每年的两个晚上“按设计”失败:夏令时开始时和夏令时结束时。
最好将DateTime.UtcNow
用于enqueue和dequeue操作。
现在要说,这不是你面临的问题。 但是要知道在你的情况下发生的比较类型,我们需要知道Expiry列的类型,如数据库中声明的和EF中声明的那样。 它是一个字符串,是日期时间还是datetimeoffset?
感谢克里斯蒂安的建议,我已经解决了这个问题:
这段代码:
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使用DateTime.Now
将比较转换为数据库中的GetDate()
。 因此,服务器之间的任何时间差都可能导致问题。
我的解决方案是将日期比较从原始查询中删除,并在所有内容都恢复时使用LINQ-to-Objects进行。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.