我花了一些时间来找到如何从方法中返回IQueryable ......我仍然想知道这是否是正确的方法。
这是我的存储库类:
public class CarRepository : ICarRepository
{
// Fake entities
private IList<Car> _entities = new List<Car>()
{
new Car() { Brand = "Lamborghini", Name = "Huracán"},
new Car() { Brand = "BMW", Name = "X6" }
};
// Allows deferred execution/further refinement
public IQueryable<Car> FindByQueryable(Expression<Func<Car, bool>> predicate)
{
var query = _entities.Where(predicate.Compile()).AsQueryable();
return query;
}
// Returning an IList or IEnumerable
public IList<Car> FindBy(Expression<Func<Car, bool>> predicate)
{
return _entities.Where(predicate.Compile()).ToList();
}
}
起初我认为类似的东西应该有效,但它没有编译:
public IQueryable<Car> FindByQueryable(Expression<Func<Car, bool>> predicate)
{
var query = _entities.Where(predicate);
return query;
}
我是否正确使用predicate.Compile()和.AsQueryable?
谢谢你的帮助! 巴斯蒂安
答案 0 :(得分:3)
因为它没有任何意义。如果要使用Queryable
方法远程查询数据库,则必须使用表达式树。使用Compile
将树转换为破坏此机会的委托。
_entities
必须是IQueryable<T>
才能定位Queryable
方法。
AsQueryable
是一种代码气味,通常表示上述错误。这是一个假的可查询。它是在内存中(除非源是真正的IQueryable;然后它执行转换)。
答案 1 :(得分:1)
原因
var query = _entities.Where(predicate);
失败是因为_entities
仅实现了IEnumerable<Car>
,而不是IQueryable<Car>
。 IEnumerable<T>
的{{3}}扩展方法需要Func<T, bool>
。 IQueryable<T>
的{{3}}扩展方法需要Expression<Func<T, bool>>
。
您可以稍微移动AsQueryable()
:
var query = _entities.AsQueryable().Where(predicate);
正如我们的回答正确指出的那样,这通常没有意义,因为它将使用本地过滤,而不是任何服务器端过滤。但是,有一些例外,它确实有意义,你的情况可能是一个这样的例外:如果你有多个ICarRepository
的实现,一些本地的,一些远程的,那么它可能是完全合理的做到你的方式'干嘛。您不希望ICarRepository
的用户必须处理是否使用委托或表达式树的问题:用户应该只使用表达式树,然后您的CarRepository
可以将这些表达式树传递给一些查询提供程序,然后该查询提供程序可以选择是将它们编译为委托,还是将它们转换为其他语言,如SQL。