协会:uniq => true并不总是返回唯一的结果

时间:2010-01-26 16:35:20

标签: ruby-on-rails

我有一组与地理相关的类:State,Msa,County,City等。这些类都来自基本的Location类。这些类在很大程度上通过称为地理的非规范化连接表相关。所以我有......

class Geography < ActiveRecord::Base
  belongs_to :state
  belongs_to :county
  belongs_to :city
  # ... etc.
end

class Location < ActiveRecord::Base
end

class State < Location
  has_many :geographies
  has_many :msas, :through => :geographies, :uniq => true
  # ... etc.
end

class Msa < Location
  has_many :geographies
  has_many :states, :through => :geographies, :uniq => true
  # ... etc.
end

现在,当我从控制台运行以下命令时:

>> msas = Msa.find(:all, :include=>"states", :conditions=>{"states_locations"=>{"id"=>"1"}})

我找回了正确数量的结果(在这种情况下为13)。但是,运行此查找调用生成的SQL会得到1,000个结果(同样地理表是各种类型的数据集合,这就是我在关联时使用:uniq选项的原因)。

SELECT          `locations`.`id` AS t0_r0, 
                `locations`.`parent_id` AS t0_r1, 
                `locations`.`type` AS t0_r2, 
                `locations`.`name` AS t0_r3, 
                `states_locations`.`id` AS t1_r0, 
                `states_locations`.`parent_id` AS t1_r1, 
                `states_locations`.`type` AS t1_r2, 
                `states_locations`.`name` AS t1_r3
FROM            `locations` 
LEFT OUTER JOIN `geography` 
ON              `locations`.`id` = `geography`.`msa_id`
LEFT OUTER JOIN `locations` states_locations 
ON              `states_locations`.`id` = `geography`.`state_id`
AND             `states_locations`.`type` = 'State'
WHERE           `states_locations`.`id` = '1'
AND             `locations`.`type` = 'Msa' 

我认为这意味着Rails将1000条记录加载到内存中,然后在Ruby中将结果减少到不同的Msas集合(在这种情况下);似乎有点低效。此外,以下后续调用会返回不同的结果:

>> msas.first.states.size    # incorrect count
=> 192
>> msas.first.states.count   # correct count
=> 1 
>> msas.first.states         # incorrect number of State objects
=> [#<State id: 1, ... >, ..., #<State id: 1, ... >]
>> msas.first.reload.states
=> [#<State id: 1, ... >]    # correct number of State objects

我的问题是:

  1. 为什么Rails在查询调用中产生的查询中不使用DISTINCT?我猜它是因为我问过它:include =&gt; :状态。我应该使用:加入吗?
  2. 为什么在调用msas.first.states时Rails会返回非唯一结果?协会不应该具有:uniq =&gt;真正强制结果的唯一性?
  3. 为什么我需要使用Rails用于位置表的状态“version”的表别名,即:conditions =&gt; {:states_locations =&gt; {:id =&gt; 1}}? Rails似乎不理解:include =&gt; :states,:conditions =&gt; {:states =&gt; {:id =&gt; 1}}。有没有办法确定性地预测表别名?
  4. 非常感谢任何见解。

    提前致谢, 杰森

1 个答案:

答案 0 :(得分:1)

那里有很多问题,让我看看这是否会有所帮助......

你是正确的,rails会触发一个sql调用来获取所有结果,然后active_record应该过滤掉唯一记录。

如果您想避免这样做,您可以执行以下操作:

has_many :states, :through => :geographies, :select => "DISTINCT states.*"

这个post有趣的分析

还有你的专栏:

msas = Msa.find(:all, :include=>"states", :conditions=>{"states_locations"=>{"id"=>"1"}})

它没有返回唯一结果,因为您没有利用您设置的关系。你可能想做类似的事情:

@msas = State.find(state_id).msas

祝你好运