ruby-on-rails - 高效的连接查询 - 可以使用 ActiveRecord 来完成吗

标签 ruby-on-rails activerecord join model-associations

我有 4 个模型,A、B、C 和 D

class A < ActiveRecord::Base
  has_many :B
  has_many :C, :through => :B
end  

class B < ActiveRecord::Base
  belongs_to :A  
  has_many   :C
  has_many   :D, :through => :C
end  

class C < ActiveRecord::Base    
  belongs_to :B
end    

class D < ActiveRecord::Base    
  belongs_to :C
end    

我有一个非常幼稚的实现,非常明显......
<% A.B.each do |b| %>
  <%= b.number %>
  <% b.C.each do |c| %>
    <%= c.name %>
  <% end %>
<% end %>

为 A 获得所有 C 的最佳方法是什么?
获得全 D 换 A 的最佳方法是什么?

我想使用带有“created_at”值的 order_by 子句来获取所有“C”,而不是通过 B 进行迭代。

可能是我错过了一些 ActiveRecord 魔法?

我很感激任何帮助。

最佳答案

首先,您需要进行一些更改。

  • class C需要关联到 D
    class C < ActiveRecord::Base
      belongs_to :B
      has_one :D
    end
    
  • 如果您想访问 AD 's,你也需要指定这个。
    class A < ActiveRecord::Base
      has_many :B
      has_many :C, :through => :B
      has_many :D, :through => :C
    end
    

  • 现在,访问所有 AC的:
    -> a = A.where(:id => 1).includes(:C).first
      A Load (0.2ms)  SELECT "as".* FROM "as" WHERE "as"."id" = 1 LIMIT 1
      B Load (0.1ms)  SELECT "bs".* FROM "bs" WHERE "bs"."a_id" IN (1)
      C Load (0.1ms)  SELECT "cs".* FROM "cs" WHERE "cs"."b_id" IN (1, 2)
     => #<A id: 1, created_at: "2012-01-10 04:28:42", updated_at: "2012-01-10 04:28:42"> 
    -> a.C
     => [#<C id: 1, b_id: 1, created_at: "2012-01-10 04:30:10", updated_at: "2012-01-10 04:30:10">, #<C id: 2, b_id: 1, created_at: "2012-01-10 04:30:11", updated_at: "2012-01-10 04:30:11">, #<C id: 3, b_id: 2, created_at: "2012-01-10 04:30:21", updated_at: "2012-01-10 04:30:21">, #<C id: 4, b_id: 2, created_at: "2012-01-10 04:30:21", updated_at: "2012-01-10 04:30:21">]
    

    注意当您调用 a.C 时,另一个查询是如何不被执行的。 .这是因为 ActiveRecord 知道您将要访问找到的 ACinclude 提供调用,并生成最少数量的查询。 D 也是如此的:
    -> a = A.where(:id => 1).includes(:D).first
      A Load (0.1ms)  SELECT "as".* FROM "as" WHERE "as"."id" = 1 LIMIT 1
      B Load (0.1ms)  SELECT "bs".* FROM "bs" WHERE "bs"."a_id" IN (1)
      C Load (0.1ms)  SELECT "cs".* FROM "cs" WHERE "cs"."b_id" IN (1, 2)
      D Load (0.1ms)  SELECT "ds".* FROM "ds" WHERE "ds"."c_id" IN (1, 2, 3, 4)
    

    说你想要所有 AD的但想要 C的命令:
    A.where(:id => 1).includes(:C).order('cs.created_at DESC').includes(:D)
    

    请注意,您还可以将其设置为关联的默认值:

    The :order option dictates the order in which associated objects will be received (in the syntax used by an SQL ORDER BY clause).

    class Customer < ActiveRecord::Base
      has_many :orders, :order => "date_confirmed DESC"
    end
    

    关于ruby-on-rails - 高效的连接查询 - 可以使用 ActiveRecord 来完成吗,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8798511/

    相关文章:

    mysql - 子女- parent 系谱 - 另一方 parent 表

    ruby-on-rails - 过滤器方法之前的 Rspec stub

    ruby-on-rails - 1 个 Heroku dyno 上有多少个 Rails 应用程序?

    ruby-on-rails - activerecord 存在子查询

    ruby-on-rails - Rails 复杂表单使用关联一次编辑多个记录

    mysql - 使用 JOINED 多个表和子查询从 MySql 获取统计信息

    ruby-on-rails - bundle 安装错误

    ruby-on-rails - Rails 4 - 无需身份验证的 Json 渲染

    sql - 当常规 where() 查询运行时,Rails 作用域不起作用

    javascript - 如何在数组中的全名后添加逗号?