如果我有4千个文件(可能还有更多文件,未检查过),我可以在Func<T,bool>
中使用IDocumentSession.Query<T>().Where(...)
,我会得到预期的结果。但是,如果我有80万份文件,那么我必须使用Expression<Func<T,bool>>
,否则我没有结果。
为什么这不一致?
问题是我有一个用于内存过滤器和数据库查询过滤器的谓词。对于内存中过滤器,集合为IEnumerable<T>
,因此它使用Func<T,bool>
,而对于数据库查询,集合为IQueryable<T>
,因此它使用Expression<Func<T,bool>>
。因此,在我的生产代码中,我有一个重载的“过滤器”方法 - 一个采用IEnumerable<T>
而另一个采用IQueryable<T>
。前者的内容为:return list.Where(getPredicate(x).Compile())
,后者的内容为:return list.Where(getPredicate(x))
显然,这看起来像重复的代码,并大喊:“请重构我并减少代码重复”。但是一旦开发人员这样做,就应该打破单元测试。但是,在传递Func<T,bool>
时,我无法让单元测试失败。
编辑:仔细检查后,它似乎与文件数量无关。如果我在单元测试中连接到相同的“生产”数据库(调用实际的生产代码),它会在使用Func<T,bool>
时返回结果,但是当我运行应用程序时它什么都不返回。很奇怪!
答案 0 :(得分:3)
嗯,在使用Func<T, bool>
时使用IQueryable
是一个非常糟糕的主意,因为这意味着您将从db中检索所有元素(因为您的Queryable将被枚举),然后过滤器将应用于IEnumerable<T>
。
如果使用Expression<Func<T, bool>>
,则将在数据库级别应用Where子句,并且仅检索已过滤的元素。
修改强>: 这种行为是完全正确的#34;并且绝对可预测。
这2个Where
是2种扩展方法。
Func
的{{1}}作为参数。 IEnumerable<T>
继承自IQueryable<T>
。因此,如果您使用IEnumerable<T>
作为参数,将采用此方法,并且在过滤之前将枚举Func
。