从我的方法返回IQueryable <t>?这是正确的方法吗?

时间:2015-04-25 10:36:57

标签: c# linq expression iqueryable

我花了一些时间来找到如何从方法中返回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?

谢谢你的帮助! 巴斯蒂安

2 个答案:

答案 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。