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

时间:2018-03-01 17:07:36

标签: c# entity-framework linq stored-procedures 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

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

发生了什么?

1 个答案:

答案 0 :(得分:3)

可组合查询的想法仅适用于基于表达式树的动态查询。如果您调用存储过程,那么实际调用存储过程 - 您必须添加List<Customer>这一事实通常意味着您实际上正在使用LINQ-to - 完全物化对象上的对象(例如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 byselect Id, Name from Customers where Region = @p0 and Value > @p1 order by Name 和列的子选择组成,以创建撰写的 SQL查询,如:

{{1}}