返回IQueryable表达式而不执行数据库查询

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了返回IQueryable表达式而不执行数据库查询相关的知识,希望对你有一定的参考价值。

虽然对使用IQueryable希望改善现有代码性能感到好奇,但我遇到了这个online test case

为了测试所提出的例子的有效性,我:

  • 创建了两个存储过程
  • 称他们如下: static void Main(string[] args) { GetCustomers(); GetRules(); } public static IQueryable GetCustomers() { var db = new DbEntities(); return db.GetCustomers().AsQueryable(); } public static IQueryable GetRules() { var db = new DbEntities(); return db.GetRules(null).AsQueryable(); }
  • 跟踪SQL Server Profiler中的db调用

根据链接中提供的示例测试问题

因此,我们对数据库执行单个复杂查询(当调用.ToList()时),而不是分别检索两个集合并将它们连接到服务器端。

我明白只要我们返回IQueryable,就不会启动db调用,直到.ToList()被调用。

但是,在我提供的代码示例中:

  • GetRules始终调用db并执行过程,无论调用方法的顺序如何,在GetCustomers之前或之后
  • 在控制台应用程序准备退出之前,GetCustomers不会调用数据库并执行该过程。

enter image description here

我的期望是这些db调用应该首先发生,因为我正在返回IQueryable。

到底是怎么回事?

答案

可组合查询的想法仅适用于基于表达式树的动态查询。如果你调用一个存储过程,你实际上是在调用一个存储过程 - 你必须添加.AsQueryable()的事实通常意味着你实际上在一个完全物化的对象上使用LINQ-to-Objects(例如List<Customer>或类似的) ,但只是将其描述为可查询。那时候:为时已晚 - 你已经执行了它。

有可能以某种方式组合存储过程,但我不会依赖它。当人们谈论IQueryable<T>时,这并不是真正的目标场景。而是用于以下事项:

IQueryable<Customer> CustomersByRegion(string region)
   => db.Customers.Where(c => c.Region == region);
...
var data = from cust in CustomersByRegion("North")
           where cust.Value > 10000
           order by cust.Name
           select new {cust.Id, cust.Name};

其中两个单独的whereorder by和列的子选择组成,以创建一个组合的SQL查询,如:

select Id, Name
from Customers
where Region = @p0 and Value > @p1
order by Name

以上是关于返回IQueryable表达式而不执行数据库查询的主要内容,如果未能解决你的问题,请参考以下文章

当我只需要计数而不读取 Document-Db 数据库中的所有文档时,如何使用 Linq 构造 IQueryable 查询?

关于IQueryable和IEnumerable

IQueryable 或 IList

每 N 个日期的 IQueryable Lambda 表达式

返回列表而不是IQueryable

2017.5.12总结