2010-01-26 33 views
1

我有一個與地理有關的類的集合:State,Msa,County,City等。這些類都從基地Location類下降。這些類大部分都是通過名爲geography的非規範化連接表相關的。所以,我有...與下面的關聯:uniq => true並不總是返回唯一的結果

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會得到1000個結果(地理表又是一種數據集市,這就是爲什麼我在關聯中使用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個,然後在紅寶石,砍伐的結果向不同組的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. 爲什麼沒有在它從查找調用產生的查詢中使用DISTINCT Rails的?我猜這是因爲我要求它:include =>:states。我應該使用:連接嗎?
  2. 爲什麼Rails在調用msas.first.states時返回非唯一結果?不應該有一個:uniq => true的協會強制執行結果的唯一性?
  3. 爲什麼我需要使用Rails用於位置表狀態「版本」的表別名,即:conditions => {:states_locations => {:id => 1}}? Rails似乎並不理解:include =>:states,:conditions => {:states => {:id => 1}}。有沒有辦法確定性地預測表別名?

任何見解將不勝感激。

在此先感謝,傑森

回答

1

你有很多問題存在,讓我看看這將有助於...

你是正確的軌道將觸發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

好運

+0

喬納森您好,感謝您的答覆。我嘗試過使用:select選項,但是,我發現:使用include時會忽略select。另外,爲了清楚起見,您引用的第二行代碼*是*在Ruby中返回唯一結果*,而不是在SQL中。我會看看喬希的帖子,看看它是否提供了進一步的見解。再次感謝。 – Jason 2010-01-28 15:30:34

+0

Josh的帖子證實Rails確實使用Ruby而不是SQL來在has_many:through => xxx,:uniq => true關聯中「唯一」。但是,它沒有提供爲什麼msas.first.states返回非唯一結果的洞察。人們會認爲,由於Rails足夠聰明,可以獨特地使用原始結果集(儘管在Ruby中),但它也足夠聰明,可以獨立於結果集中對象的關聯。也許我需要深入瞭解Rails中的關聯代碼。 – Jason 2010-01-28 15:53:26

相關問題