簡體   English   中英

帶有ID聯接的Rails 3 Active Record查詢接口的問題

[英]Problems with Rails 3 Active Record Query Interface with join on ID

我一直在與Rails 3活動記錄查詢接口有問題。 我有一個查找表(lookups),一個主表(through_references)和一個通過/聯接表through_tables。 因此,這是我使用has_many:through設置的HABTM配置。

更新:這里要特別注意的是,當我執行這些聯接時,我一直在聯接ID,以提供記錄過濾。 看來這不適用於Active Record查詢接口。 如果您不想查看我的工作的血腥細節,可以跳到下面查看我的解決方法。

我們還將有許多主要項(through_references表)應該可以具有查找項的任意組合,並可以方便地單擊相關的查找項,例如復選框。

我已將代碼發布在github上 github源代碼上有很多解釋。 要查看結果,請轉到查找索引頁面。 請注意,您將需要使用腳手架代碼創建記錄。

我還擁有在heroku上運行的代碼,以及更多的解釋和示例。

class Lookup < ActiveRecord::Base
  has_many :fk_references
  has_many :through_tables
  has_many :through_references, :through => :through_tables
  attr_accessible :name, :value
end

class ThroughTable < ActiveRecord::Base
  belongs_to :through_reference
  belongs_to :lookup
  attr_accessible :description, :through_reference_id, :lookup_id
end

class ThroughReference < ActiveRecord::Base
  has_many :through_tables
  has_many :lookups, :through => :through_tables
  attr_accessible :description
end

如果我們想列出所有查找項目以及與之對應的主要項目,則可以將“查找”表與主要項目(through_references)表一起加入。 對應的SQL:

SELECT * FROM lookups
  LEFT OUTER JOIN through_tables ON (lookups.id = through_tables.lookup_id AND through_tables.through_reference_id = 1)
  LEFT OUTER JOIN through_references ON through_references.id = through_tables.through_reference_id
  ORDER BY lookups.id

返回記錄:

1;“Lookup Item 1”;“1”;“2012-06-06 17:14:40.819791”;“2012-06-06 17:14:40.819791”;1;1;1;“Main Item 1 has Lookup item 1”;“2012-06-06 17:17:31.355425”;“2012-06-06 17:17:31.355425”;1;“Main Item 1”;“2012-06-06 17:16:30.004375”;“2012-06-06 17:16:30.004375”

2;“Lookup Item 2”;“2”;“2012-06-06 17:14:59.584756”;“2012-06-06 17:14:59.584756”;;;;“”;“”;“”;;“”;“”;“”

3;“Lookup Item 3”;“3”;“2012-06-06 17:15:14.700239”;“2012-06-06 17:15:14.700239”;2;1;3;“Main Item 1 has Lookup item 3”;“2012-06-06 17:17:53.169715”;“2012-06-06 17:17:53.169715”;1;“Main Item 1”;“2012-06-06 17:16:30.004375”;“2012-06-06 17:16:30.004375”

這是我所期望的。

===使用自定義左聯接的Active Record查詢接口

Lookup.joins(“LEFT OUTER JOIN through_tables ON (lookups.id = through_tables.lookup_id AND through_tables.through_reference_id = 1)” ).includes(:through_references).order(‘lookups.id’)

從Active Record查詢界面返回的內容(請注意,我向下瀏覽Active Record層次結構):

Lookup ID Lookup Name Lookup Value Through Table ID Through Table Description Main Item ID Main Item Description
1 Lookup Item 1 1 1 Main Item 1 has Lookup item 1 1 Main Item 1
1 Lookup Item 1 1 3 Main Item 2 has Lookup item 1 2 Main Item 2
2 Lookup Item 2 2 4 Main Item 2 has Lookup item 2 2 Main Item 2
3 Lookup Item 3 3 2 Main Item 1 has Lookup item 3 1 Main Item 1

這不是我所期望的。

我們這里擁有的內容與簡單的左連接(沒有AND子句)相同。 這告訴我在Active Record查詢接口中AND子句被忽略。

===使用find_by_sql方法的活動記錄查詢接口

Lookup.find_by_sql("SELECT * FROM lookups LEFT OUTER JOIN through_tables ON (through_tables.lookup_id = lookups.id AND through_tables.through_reference_id = 1) LEFT OUTER JOIN through_references ON through_references.id = through_tables.through_reference_id ORDER BY lookups.value, through_references.id" )

從Active Record查詢界面返回的內容(請注意,我向下瀏覽Active Record層次結構):

Lookup ID   Lookup Name     Lookup Value    Through Table ID    Through Table Description   Main Item ID    Main Item Description
1   Lookup Item 1   1   3   Main Item 2 has Lookup item 1   2   Main Item 2
1   Lookup Item 1   1   1   Main Item 1 has Lookup item 1   1   Main Item 1
    Lookup Item 2   2   No through_tables entry
1   Lookup Item 3   3   3   Main Item 2 has Lookup item 1   2   Main Item 2
1   Lookup Item 3   3   1   Main Item 1 has Lookup item 1   1   Main Item 1

這里的結果太瘋狂了!

這是一個錯誤,是預期的效果,還是我缺少了什么?

我希望有一個干凈的方法,而不必生成兩個結果集,並通過代碼合並它們。

我找到了一種解決方法。 問題似乎是Active Record無法識別對ID進行過濾的聯接(LEFT OUTER JOIN xyz ON xyz.id = ID)。

我的變通辦法涉及創建一個存儲過程或函數,該過程將ID作為參數,在數據庫中進行聯接,並返回一個不錯的平面記錄集。

請參閱: Heroku演示頁面(跳到底部)

請注意,我沒有將其標記為解決方案,因為這是一種變通方法,並且與活動記錄無關。

好吧,閱讀github項目,我看到了:

我真正想做的是擁有所有查找項目的列表,如果有匹配的Main Items,請將它們附加到返回的記錄上,否則,我希望為null。 這是我使用了10多年的技術。

我在想這個問題恰恰是您想要這樣做,那時候讓渴望加載的Rails處理它會更自然,因此您已經將注意力集中在通過單個大規模連接獲取所有內容上。

我要做的是這樣的:

Lookup.where(..在此處插入任何需要的條件...)。includes(:through_tables)

然后,ActiveQuery將在一個查詢中獲取所有Lookup,然后使用預先加載來獲取包含語句中命名的任何關聯,每個關聯一個查詢。

請注意,我並不是說聯接是不好的,只是說這是在Rails中進行連接的更自然的方法。 我喜歡使用Preloader http://apidock.com/rails/ActiveRecord/Associations/Preloader將需要加載哪些內容的決定與要獲取哪些數據的決定區分開來。 我發現這對控制器很有幫助-讓模型決定條件是什么,但讓控制器決定需要加載哪些對象。

高溫超導

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM