高效的连接查询 - 可以使用ActiveRecord完成

时间:2012-01-10 04:18:07

标签: 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 %>

获得All C for A的最佳方式是什么? 获得All D for A的最佳方式是什么?

我希望使用带有“created_at”值的order_by子句而不是迭代B来获取所有'C'。

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

我感谢任何帮助。

1 个答案:

答案 0 :(得分:6)

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

  1. class C需要与D

    的关联
    class C < ActiveRecord::Base
      belongs_to :B
      has_one :D
    end
    
  2. 如果您想访问A的{​​{1}},则还需要指定此内容。

    D
  3. 现在,要访问class A < ActiveRecord::Base has_many :B has_many :C, :through => :B has_many :D, :through => :C end A的所有内容:

    C

    注意调用-> 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">] 时如何不执行其他查询。这是因为ActiveRecord知道您希望通过a.C调用访问找到的A C,并生成最少数量的查询。同样适用于include&#39; s:

    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) A,但希望D订购:

    C

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

      

    A.where(:id => 1).includes(:C).order('cs.created_at DESC').includes(:D) 选项指示将接收关联对象的顺序(使用SQL :order子句使用的语法)。

    ORDER BY