繁体   English   中英

针对实体框架的LINQ查询如何将日期传递给SQL Server?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM