关于linq to sql:如果我使用IEnumerable<>进行过滤,我的LinqToSql执行是否会被删除?

Will my LinqToSql execution be deffered if i filter with IEnumerable<T> instead of IQueryable<T>?

我一直使用这些通用的EntityObjectFilters作为"管道和过滤器"方法,从集合中查询具有ID的特定项:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static class EntityObjectFilters
{
    public static T WithID<T>(this IQueryable<T> qry,
       int ID) where T : IEntityObject
    {
        return qry.SingleOrDefault<T>(item => item.ID == ID);
    }

    public static T WithID<T>(this IList<T> list,
        int ID) where T : IEntityObject
    {
        return list.SingleOrDefault<T>(item => item.ID == ID);
    }
}

…但我想:"我能通过为所有IEnumerable类型创建一个扩展来简化这一点吗?"所以我想到了这个:

1
2
3
4
5
6
7
8
public static class EntityObjectFilters
{
    public static T WithID<T>(this IEnumerable<T> qry,
       int ID) where T : IEntityObject
    {
        return qry.SingleOrDefault<T>(item => item.ID == ID);
    }
}

现在,虽然这似乎产生了相同的结果,但我想知道,当应用于IQueryables时,表达式树将被传递给linqtosql作为SQL代码进行计算,还是将我的qry首先进行整体计算,然后使用Funcs进行迭代?

我怀疑(根据理查德的回答)后者是真的,这显然是我不想要的。我希望得到相同的结果,但IQueryable的延迟SQL执行带来的额外好处。有人能为我确认实际会发生什么,并就如何工作提供简单的解释吗?

编辑:

我使用的解决方案

1
2
3
4
5
6
7
8
    public static T WithID<T>(this IEnumerable<T> qry,
        int ID) where T : DomainBase
    {
        if (qry is IQueryable<T>)
            return ((IQueryable<T>)qry).SingleOrDefault<T>(item => item.ID == ID);
        else
            return qry.SingleOrDefault<T>(item => item.ID == ID);
    }

不,当qry键入IEnumerable时,它将调用Enumerable.SingleOrDefault而不是Queryable.SingleOrDefault。lambda表达式将转换为委托而不是表达式树,并且不会使用SQL。

注意,SingleOrDefault一开始并不使用延迟执行——它总是立即执行的——但不同之处在于执行查询的地方。几乎可以肯定的是,您希望数据库能够做到这一点。如果您使用简化版本查看日志,您将看到所有结果都被获取了,而使用IQueryable重载,SQL将包含相关的筛选。