在不执行数据库查询的情况下返回 IQueryable 表达式
Returning IQueryable expressions without executing database queries
虽然对希望提高现有代码性能的 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
中跟踪数据库调用
根据link
中提供的样题
As a result, we execute a single complex query against the database (when .ToList() is called) instead of retrieving two collections separately and joining them server-side.
我明白,只要我们返回 IQueryable,就不会启动任何数据库调用,直到 .ToList() 被调用在某一时刻。
但是,在我提供的代码示例中:
- GetRules 总是在 GetCustomers
之前或之后调用数据库并执行过程,而不管调用方法的顺序如何
- GetCustomers 在控制台应用程序准备好退出之前不会调用数据库并执行过程。
我的期望是这些数据库调用中没有一个应该首先发生,因为我正在返回 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};
这两个单独的 where
由 order by
和 sub-selection 列组成,从而创建一个 composed SQL 查询类似:
select Id, Name
from Customers
where Region = @p0 and Value > @p1
order by Name
虽然对希望提高现有代码性能的 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
中跟踪数据库调用
根据link
中提供的样题As a result, we execute a single complex query against the database (when .ToList() is called) instead of retrieving two collections separately and joining them server-side.
我明白,只要我们返回 IQueryable,就不会启动任何数据库调用,直到 .ToList() 被调用在某一时刻。
但是,在我提供的代码示例中:
- GetRules 总是在 GetCustomers 之前或之后调用数据库并执行过程,而不管调用方法的顺序如何
- GetCustomers 在控制台应用程序准备好退出之前不会调用数据库并执行过程。
我的期望是这些数据库调用中没有一个应该首先发生,因为我正在返回 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};
这两个单独的 where
由 order by
和 sub-selection 列组成,从而创建一个 composed SQL 查询类似:
select Id, Name
from Customers
where Region = @p0 and Value > @p1
order by Name