过滤 IQueryable返回错误结果
我刚刚遇到了相当令人惊讶的问题。
情况很简单:返回当前活动的所有实体,这意味着:根据其布尔 Active 属性过滤 GetAll()
方法返回的所有结果
public IQueryable<T> GetAllActive()
{
return implementation.GetAll().Where(a => ((IDeactivable)a).Active);
}
,其中 GetAll()
方法实现对象的定义为:
public IQueryable<T> GetAll();
问题是,GetAllActive()
返回所有记录,无论其 Active 属性的值如何,就像没有Where 子句一样。
可能是什么原因?
注意:代码已简化,检查T
类型以实现IDeactivable
接口。运行时也不会引发异常。
编辑: 实现对象返回的 IQueryable 来自 NHibernate
Edit2: 我使用以下代码来检查实体的实际值(除了使用 VS 调试器之外):
foreach (var a in active) { //active -> filtered IQueryable before return
_logger.Warn(a.Id);
_logger.Warn(((IDeactivable)a).Active);
}
结果是:
11/30/2011 18:10:00 WARN xxx.Repository`1.GetAllActive: 70db43fa-2361-4c1f-a8e5-9fab012b5a2b
11/30/2011 18:10:01 WARN xxx.Repository`1.GetAllActive: False
11/30/2011 18:10:02 WARN xxx.Repository`1.GetAllActive: 5493c9bb-ec6e-4690-b5d6-9fab012b5b16
11/30/2011 18:10:02 WARN xxx.Repository`1.GetAllActive: True
I have just run into quite surprising problem.
The case is simple: return all entities that are currently active, which means: filter all result returned by GetAll()
method according to their Boolean Active property
public IQueryable<T> GetAllActive()
{
return implementation.GetAll().Where(a => ((IDeactivable)a).Active);
}
where GetAll()
method of implementation object is defined as:
public IQueryable<T> GetAll();
The problem is, that GetAllActive()
returns all the records, regardless of value of their Active property, just like there is no Where clause.
What could be the reason for it?
Note: The code is simplified, T
type is checked to implement the IDeactivable
interface. Also no exception is thrown during at runtime.
Edit: IQueryable returned by implementation object comes from NHibernate
Edit2: I have used following code to check the actual values for the entities (besides using VS Debugger):
foreach (var a in active) { //active -> filtered IQueryable before return
_logger.Warn(a.Id);
_logger.Warn(((IDeactivable)a).Active);
}
the result was:
11/30/2011 18:10:00 WARN xxx.Repository`1.GetAllActive: 70db43fa-2361-4c1f-a8e5-9fab012b5a2b
11/30/2011 18:10:01 WARN xxx.Repository`1.GetAllActive: False
11/30/2011 18:10:02 WARN xxx.Repository`1.GetAllActive: 5493c9bb-ec6e-4690-b5d6-9fab012b5b16
11/30/2011 18:10:02 WARN xxx.Repository`1.GetAllActive: True
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
当您返回
IQueryable
时,您实际上并未返回结果集。您返回的是一个可以查询的对象。.Where()
方法的执行被推迟,直到您(或有人调用您的方法)实际上强制执行 Linq 链。这使得下游客户端可以将其额外的 Linq 方法应用于结果,并且仍然对整个 Linq 链进行惰性评估。因此,当您说 IQueryable时, 正在返回所有记录,您可能正在调试器中查看结果,并且它向您显示未经过滤的原始数据集(因为
.Where()
尚未执行然而)。转换为
IEnumerable
有效的原因是它触发 Linq 命令链的执行,并且结果是一个真实的列表,而不是可以查询的对象.调用ToList()
或ToArray()
也会触发执行。简而言之,确保在测试过程中从 Linq 方法中看到正确结果的唯一方法是强制执行 Linq 链:
了解其工作原理,请参阅使用延迟执行。它包含一个示例,展示了如何从
using
块返回IQueryable
时遇到麻烦,因为IQueryable
对象已被释放在查询执行之前。When you return an
IQueryable<T>
, you are not actually returning a result set. What you are returning is an object that can be queried.Execution of the
.Where()
method is deferred until you (or someone calling your method) actually compels execution of the Linq chain. This is what makes it possible for downstream clients to apply their additional Linq methods to the result, and still get lazy evaluation for the entire Linq chain.So when you say that the
IQueryable<T>
is returning all records, you're probably looking at the result in the debugger, and it's showing you the original data set without the filtering (since the.Where()
hasn't executed yet).The reason casting to
IEnumerable
works is because it triggers execution of the Linq command chain, and the result is a bonafide list, rather than an object that can be queried. CallingToList()
orToArray()
will also trigger execution.In short, the only way you can be sure you're seeing the correct result from your Linq methods during your testing process is to force execution of the Linq chain:
For a little flavor of how this works, see Working with Deferred Execution. It contains an example showing how you can actually get into trouble returning an
IQueryable
from ausing
block, because theIQueryable
object gets disposed before the query executes.我尝试了几种不同的方法,最后我发现我的代码的一部分尚未测试。事实证明,在使用Where子句时,对NHibernate的LINQ查询导致了一些我以前没有注意到的问题。
最终,我发现我使用了错误版本的 LINQ to NHibernate QueryProvider(不是 NH 3.0 中包含的版本),这是一个已知问题。现在我已经摆脱了它,一切都正常了。谢谢你们的帮助,伙计们!你为我指明了正确的方向。
以下线程中描述了提到的问题:
linq 查询问题
I have tried several different approaches and I finally I have found a part of my code not tested yet. It turned out that LINQ Queries to NHibernate caused some issues when using Where clause, that I have not noticed before.
Eventually, I figured out, that I am using a wrong version of LINQ to NHibernate QueryProvider (not the one included in NH 3.0) and that is a known issue. Now that I have get rid of it, everything works fine. THANK YOU FOR YOUR HELP, GUYS! You pointed me out to the right direction.
Mentioned issue is described in following thread:
Problem with linq query