我正在使用Rails 3.0.7。
我有一些多对多和一些一对多的关联无法加载。
我的协会是:
Person has_many :friends
Person has_many :locations through=> :location_histories
Location belongs_to :location_hour
Location_hour has_many :locations
在我的控制器中,我有以下内容:
@people = Person.includes([[:locations=>:location_hour],:friends]).where("(location_histories.current = true) AND (people.name LIKE ? OR friends.first_name LIKE ? OR friends.last_name LIKE ? OR (friends.first_name LIKE ? AND friends.last_name LIKE ?))").limit(10).all
然后在我看来,我有:
<% @people.each do |person| %>
<tr>
<td><%= link_to person.name, person %></td>
<td><%= link_to person.friends.collect {|s| [s.full_name]}.join(", "), person.friends.first %></td>
<td><%= link_to person.locations.current.first.name, person.locations.current.first %></td>
</tr>
<% end %>
locations.current是一个定义为:
的范围scope :current, lambda {
where("location_histories.current = ?", true)
}
这按预期工作,首先生成2个数据库调用:一个用于获取人员ID列表,然后是一个大数据库调用,其中所有内容都已正确连接。问题是,之后有以下几行数据库调用:
SELECT 'friends'.* from 'friends' WHERE ('friends'.person_id = 12345)
因此对于视图中循环的每次迭代。不用说这需要一段时间。
我认为.all会强制加载。任何人都知道这里发生了什么? 这在ActiveRecord上花费超过3秒。太长了。
我非常感谢任何建议。
感谢。
答案 0 :(得分:1)
行。终于解决了。
我需要调用两个连接和包含。我还必须从连接中删除:locations_current关联。它试图通过
... LEFT OUTER JOIN `locations` ON `location_histories`.current = 1 ...
当然,这不是一个有效的关联。似乎“当前”条款已被转移到JOINS中。
所以现在我有以下,这是有效的。
@people = Person.joins([[:locations=>:location_hour],:friends]).includes([[:locations=>:location_hour],:friends]).where("(location_histories.current = true) AND (people.name LIKE ? OR friends.first_name LIKE ? OR friends.last_name LIKE ? OR (friends.first_name LIKE ? AND friends.last_name LIKE ?))")
总结:
1)我需要同时使用连接和包含来加载和正确解释.while()条件
2)我需要在条件中保持与条件(即:current_locations)的关联。
如果这对你来说似乎是一个明显的错误,请纠正我。它似乎工作。这将活动记录时间降低到不到1秒。
组合连接和包含是否常见?
谢谢!
答案 1 :(得分:0)
我已经找到问题的一部分(虽然仍有一些意想不到的行为)。 我有几个范围,例如locations.current,如上所述定义。
我已将此逻辑移至关联。所以在我的Person模型中我现在有了
has_many :current_locations, :source => :location, :through => :location_histories, :conditions => ["`location_histories`.current = ?", true]
我打电话给
Person.current_locations.first
而不是
Person.locations.current.first.
所以现在包含按预期进行了预先加载。
问题在于这搞砸了搜索。出于某种原因,当我包含where子句时,现在一切似乎都挂了。对于我添加到include中的每个表,以及当我包含所有必要的表时,事情首先变得非常慢。没有错误。
我知道这一点:当我在where子句中添加符号时,Rails在查询期间执行外连接(如here所述),这是预期的。但是为什么这会导致整个事情崩溃?
(这里的一个小问题是我需要进行字符串比较。为了获得正确的连接,我调用.where
.where(:table =>{:column=> 'string'})
相当于
table.column = 'string'
SQL中的但是我需要
table.column LIKE '%string%'
答案 2 :(得分:0)
奇怪的是,对我来说,我有以下行为:
# fails to eager load tags--it only loads one of the tags for me, instead of all of them.
Product.find(:all, :conditions => ["products_tags.tag_id IN (?)", 2], :include => [:tags])
但这成功了
Product.find(:all, :conditions => ["products_tags.tag_id IN (?)", 2], :include => [:tags], :joins => [:tags])
就像内部联接表上的查询以某种方式搞乱了急切的加载。所以你的答案可能是正确的。但这里可能有些奇怪的事情发生。 (这里是Rails 2.3.8)。