小编典典

将 IQueryable 与 Linq 一起使用

all

IQueryable在 LINQ 的上下文中有什么用?

它是否用于开发扩展方法或任何其他目的?


阅读 93

收藏
2022-05-07

共1个答案

小编典典

回答非常完整,但我想我也会从用户的角度添加一些内容......

本质上,它的工作非常类似于IEnumerable<T>- 表示可查询的数据源 - 不同之处在于各种 LINQ 方法(on Queryable)可以更具体,使用Expression树而不是委托(这是Enumerable使用的)构建查询。

表达式树可以由您选择的 LINQ 提供程序检查并转化为实际查询 - 尽管这本身就是一种黑色艺术。

这真的取决于ElementTypeExpression并且Provider- 但实际上,作为用户,您很少需要关心这一点。只有 LINQ实现者需要知道血淋淋的细节。


重新评论;例如,我不太确定您想要什么,但请考虑 LINQ-to-SQL;这里的中心对象是 a DataContext,它代表我们的数据库包装器。这通常具有每个表的属性(例如Customers),并且表实现了IQueryable<Customer>。但是我们并没有直接使用那么多;考虑:

using(var ctx = new MyDataContext()) {
    var qry = from cust in ctx.Customers
              where cust.Region == "North"
              select new { cust.Id, cust.Name };
    foreach(var row in qry) {
        Console.WriteLine("{0}: {1}", row.Id, row.Name);
    }
}

这变成(由 C# 编译器):

var qry = ctx.Customers.Where(cust => cust.Region == "North")
                .Select(cust => new { cust.Id, cust.Name });

(由 C# 编译器)再次将其解释为:

var qry = Queryable.Select(
              Queryable.Where(
                  ctx.Customers,
                  cust => cust.Region == "North"),
              cust => new { cust.Id, cust.Name });

重要的是,静态方法Queryable采用表达式树,而不是常规的 IL,它被编译为对象模型。例如 - 只看“哪里”,这给了我们类似的东西:

var cust = Expression.Parameter(typeof(Customer), "cust");
var lambda = Expression.Lambda<Func<Customer,bool>>(
                  Expression.Equal(
                      Expression.Property(cust, "Region"),
                      Expression.Constant("North")
                  ), cust);

... Queryable.Where(ctx.Customers, lambda) ...

编译器不是为我们做了很多事情吗?这个对象模型可以被撕开,检查它的含义,然后由 TSQL 生成器重新组合在一起——给出如下内容:

 SELECT c.Id, c.Name
 FROM [dbo].[Customer] c
 WHERE c.Region = 'North'

(字符串可能最终作为参数;我不记得了)

如果我们只使用委托,这一切都不可能实现。这就是Queryable/的要点IQueryable<T>:它提供了使用表达式树的入口点。

所有这一切都非常复杂,因此编译器让我们变得轻松而轻松是一件好事。


从用户的角度来看,主要区别在于,当您使用IQueryable<T>(使用正确支持事物的提供者)时,您可以节省大量资源。

例如,如果您正在处理具有许多 ORM
系统的远程数据库,您可以选择以两种方式从表中获取数据,一种返回IEnumerable<T>,另一种返回IQueryable<T>.
例如,假设您有一个 Products 表,并且您想要获取成本大于 25 美元的所有产品。

如果你这样做:

 IEnumerable<Product> products = myORM.GetProducts();
 var productsOver25 = products.Where(p => p.Cost >= 25.00);

这里发生的是数据库加载所有产品,并将它们通过网络传递给您的程序。然后您的程序过滤数据。本质上,数据库做了一个SELECT * FROM Products,并返回每一个产品给你。

IQueryable<T>另一方面,使用合适的提供商,您可以:

 IQueryable<Product> products = myORM.GetQueryableProducts();
 var productsOver25 = products.Where(p => p.Cost >= 25.00);

代码看起来一样,但这里的区别是执行的 SQL 将是SELECT * FROM Products WHERE Cost >= 25.

从您作为开发人员的 POV 来看,这看起来是一样的。但是,从性能的角度来看,您可能只能通过网络返回 2 条记录,而不是 20,000 条......

2022-05-07