【问题标题】:ActiveRecord Query ChainsActiveRecord 查询链
【发布时间】:2011-08-30 18:08:37
【问题描述】:

这个 ruby​​/rails 结构总是让我感到困惑:

User.where(:name => "Thiago").limit(3).using(:slave_one)

这必须从左到右执行,以便每个连续的调用都有一个接收器。所以我们从 User 类开始,在它上面调用where,它返回一个ActiveRecord::Relation 的实例。然后在该实例上调用limit,返回另一个ActiveRecord::Relation 实例。然后在该实例上调用using(恰好选择了一个分片)。我猜,整个事情在ActiveRecord::Relation 对象中构建了一个SQL 查询。我的问题是,“是什么触发了查询的实际执行”?它不能在链中的任何特定点执行,因为链中可能存在进一步修改查询的后继。即使在using 返回之后,查询仍然无法执行,因为它无法知道是否附加了附加方法到链上。显然,它确实是在构建后执行查询,那么查询实际上是如何调用的呢?


谢谢...我现在看到链中方法的名称具有“语义”。有些人会进一步修改正在构建的查询。最后一个也是唯一的最后一个可能是需要获取数据的类型。

【问题讨论】:

    标签: ruby-on-rails ruby activerecord rails-activerecord active-record-query


    【解决方案1】:

    ActiveRecord::Relation 不会费心与数据库对话,直到您要求它提供一些数据。例如:

    User.where(:name => "Thiago").limit(3).using(:slave_one).count
    # talks to the database here ----------------------------^^^^^
    

    如果您查看 ActiveRecord::Relation,您会发现它包含 ActiveRecord::QueryMethods,其中的大部分内容如下所示:

    def x(*args)
      relation = clone
      # merge args into relation
      relation
    end
    

    所以关系只是一块一块地构建一个查询,直到你做一些需要执行查询的事情;然后它将构建适当的 SQL,将其发送到数据库,并使用数据库发回的内容(理论上)做一些有用的事情。

    另请注意,每个 QueryMethods 方法都返回一个克隆和修改的关系,因此您可以执行以下操作:

    r1 = User.where(:name => 'Pancakes')
    r2 = r1.limit(3)
    

    然后使用r1 抓取所有匹配项,或使用r2 抓取其中三个。

    【讨论】:

      【解决方案2】:

      这种构造(查询在构建时永远不会执行)是有意的。这称为延迟加载。

      查询在您第一次向关系请求数据时执行。 IE 如果你有:

      @users = User.where(:name => "Thiago").limit(3).using(:slave_one)
      @users.first.name #the query executes here
      

      通常这将在视图模板中调用查询数据的第一行时执行。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-02-21
        • 2011-04-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-10-04
        相关资源
        最近更新 更多