这似乎是一种不一致,但我可能只是遗漏了一些明显的东西。基本查询是:
var events = db.tbl_special_events.Where(x => x.TimeStamp >= startDate);
当我运行以下代码块时出现明显的不一致:
int c1 = 0;
foreach (var e in events)
{
if (e.TimeStamp.DayOfWeek.ToString() == "Tuesday") c1++;
}
int c2 = events.Where(e => e.TimeStamp.DayOfWeek.ToString() == "Tuesday").Count();
在那之后,c1是1832,但是c2是0.我缺少什么?
答案 0 :(得分:2)
我重新创建了这个测试,发现它可能与DateTime函数直接相关。
生成的查询:
exec sp_executesql N'SELECT [t0].[User_ID], [t0].[Email], [t0].[Password], [t0].[BrandID], [t0].[CustomerID], [t0].[Created], [t0].[EndDate], [t0].[AccountStatusID], [t0].[Verified], [t0].[ResetPasswordFailCount], [t0].[ResetPasswordLocked]
FROM [dbo].[User] AS [t0]
WHERE ((CONVERT(NVarChar,CONVERT(Int,(DATEPART(dw, [t0].[Created]) + (@@DATEFIRST) + 6) % 7))) = @p0) AND ([t0].[BrandID] = @p1)',N'@p0 nvarchar(4000),@p1 int',@p0=N'Tuesday',@p1=3
注意@ p0 = N'Tuesday'
请记住,IQueryable和IEnumerable的不同之处在于IEnumerable表示实际的.net对象,IQueryable将您的表达式转换为用于查询数据库的实际SQL语句。因此,您在该表达式中提供的任何值实际上都会发送到数据库。
它返回0结果,因为没有匹配。原因是,SQL中的日期转换返回2而不是'星期二'。如果你在LINQ WHERE子句中用2替换星期二,你可以测试它,它实际上是可行的。这将在枚举之后起作用,因为结果将成功映射到一个可用的.net对象,其中DateTime.DayOfWeek转换为“Tuesday”将正常工作。
答案 1 :(得分:1)
您的计数是IQueryable<Event>
,而e
是枚举的实例。因此,某些操作可能无法正常工作,因为它们无法转换为SQL [编辑:或将在无意义的SQL中翻译]。
要确保您的Where
子句有效,请在其前面添加AsEnumerable()
。这会将IQueryable<Event>
转换为IEnumerable<Event>
并告诉linq提供程序此时应该停止生成SQL。
所以,这个陈述应该提供正确的结果:
int c2 = events.AsEnumerable()
.Where(e => e.TimeStamp.DayOfWeek.ToString() == "Tuesday")
.Count();
无法转换的实际代码导致SQL中的问题为e.TimeStamp.DayOfWeek.ToString()
。
或者,您可以使用System.Data.Objects.SqlClient.SqlFunctions
(doc here)类来提示linq提供程序在SQL中应该执行的操作。
修改强>
正如@Servy指出这是一个Linq to SQL问题。但是,问题很常见,所以我留下答案,不要删除它。
再次看OP,整个游戏可能会有另一个变量......延迟加载。
在foreach循环中,TimeStamp是延迟加载的。在计数查询中,提供程序尝试构造SQL查询,在此构造期间,它可能无法使用ToString
(已知存在问题)并将e.TimeStamp.DayOfWeek.ToString()
评估为不同于{{ 1}}。
"Tuesday"
强制提供程序停止生成SQL,以便AsEnumerable()
再次延迟加载。
确切地说明正在发生的事情的唯一方法是在数据库(例如SQL Server Profiler)上使用跟踪工具来实际查看在服务器上执行的查询(或查询)。
修改2
在@Sinaesthetic's answer的基础上,返回0的原因是查询尝试将e.TimeStamp
与"4"
进行比较,返回false,因此正确的结果为"Tuesday"
。< / p>
可以通过执行
进行测试false
反对DB。
但是,这也表明由提供者决定它生成什么SQL。此外,由提供者决定它支持哪些语句以及哪些语句不支持。
它还表明 使用select ((CONVERT(NVarChar,CONVERT(Int,(DATEPART(dw, getdate()) + (@@DATEFIRST) + 6) % 7))))
来停止SQL生成过程可能会对查询的语义评估产生影响 。