Activerecord:包含其他条件

时间:2011-03-30 00:19:38

标签: ruby-on-rails-3 activerecord

如何在ActiveRecord中指定JOIN ON子句?

对ActiveRecord.find方法使用:include参数时,创建的SQL使用带有foreign key = primary key的ON子句的JOIN操作。例如:

A.find(:include => :B) 

结果

select ... from A 
  left outer join B on B.a_id=A.id

现在我的例子:

A.find(:include => { :B => { :include => :C } } )

结果:

select ... from A 
  left outer join B on B.a_id=A.id 
  left outer join C on C.b_id=B.id

但是,我只想要C中的一些记录,但如果没有找到,那么我仍然想要A和B

这不起作用

A.find(:include => { :B => { :include => :C } },
  :condition => "C.rec<10" )

因为这导致:

select ... from A 
  left outer join B on B.a_id=A.id 
  left outer join C on C.b_id=B.id
  where C.rec<10

如何指示AcriveRecord创建这样的查询?

select ... from A 
  left outer join B on B.a_id=A.id 
  left outer join C on C.b_id=B.id and C.rec<10

2 个答案:

答案 0 :(得分:1)

我不知道用关联方法添加ON子句的方法。

对于您的示例,仅在C中仅加载一些记录的最简单方法是在B中定义与条件的关联。(请参阅此ActiveRecord::Associations API documentation的“关联的加载加载”部分。)

class A < ActiveRecord::Base
    has_many :bs
end

class B < ActiveRecord::Base
    has_many :cs
    has_many :cs_with_rec_less_than_10, :class_name => 'C', :conditions => ['rec < 10']
end

class C < ActiveRecord::Base
end

您可以致电:

A.includes(:bs => :cs_with_rec_less_than_10)

这将生成3个查询,每个表一个,而不是在1个查询中加入它们。例如,如果A和B各包含2个ID为1和2的记录:

SELECT "as".* FROM "as"
SELECT "bs".* FROM "bs" WHERE ("bs".a_id IN (1,2))
SELECT "cs".* FROM "cs" WHERE ("cs".b_id IN (1,2) AND (rec < 10))

如果使用左连接进行单个查询很重要,我会手动编写查询,使用ActiveRecord::Base.connection.execute执行查询,并直接处理结果。

答案 1 :(得分:-1)

这可能不是最具铁路性的解决方案,但是当我绝望地寻找Railstic风暴时,我发现它很方便。

我相信你可以弄清楚如何处理以下示例,并希望你能以某种方式发现它有用。

@visits = Visit.select("v.*, c.*" ).
  where("u.id = ?", session[:user_id]).
  joins( %{ as v inner join customers as c on (v.customer_id = c.id)
      inner join businesses as b on (v.business_id = b.id)
      inner join managers as m on (b.manager_id = m.id)
      inner join users as u on (m.user_id = u.id)
      } ).
  order(' v.created_at DESC')