2

我正在Rails 4.1中構建一個飲食分析應用程序。我有一個模型,FoodEntry,其中一個簡單的級別都有一個quantity值並參照FoodMeasureRails:多態關聯,不同的選項取決於類型?

class FoodEntry < ActiveRecord::Base 
    belongs_to :food 
    belongs_to :measure 
end 

但是我實際上有兩種不同類型的措施,標準通用測量(杯子,茶匙,克等)以及食品特有的措施(西蘭花頭,中型香蕉,大罐等)。聽起來像一個多態關聯權的情況?例如

class FoodEntry < ActiveRecord::Base 
    belongs_to :food 
    belongs_to :measure, polymorphic: true # Uses measure_id and measure_type columns 
end 

class StandardMeasure < ActiveRecord::Base 
    has_many :food_entries, as: :measure 
end 

class FoodMeasure < ActiveRecord::Base 
    has_many :food_entries, as: :measure 
end 

事情是,特定於食物的措施來自遺留數據庫轉儲。這些記錄由它們的組合food_iddescription唯一標識 - 它們未提供單列主鍵(由於有多種食物具有相同的測量描述但數字數據不同,因此它們本身並不是唯一的)。因爲我正在導入到Rails Postgres數據庫,所以我可以添加一個代理主鍵 - Rails期望的自動遞增整數id列。但我不想在我的FoodEntry模型中使用這個id作爲參考,因爲當(外部提供的)數據被更新並且我不得不重新導入時,它對保持參考完整性保持不變是一個相當大的挑戰。基本上,這些ids完全可以改變,所以我寧願直接參考food_iddescription

幸運的是,這不是很困難的使用對相關聯的範圍,爲此在Rails的:

class FoodEntry < ActiveRecord::Base 
    belongs_to :food 
    belongs_to :measure, ->(food_entry) { where(food_id: food_entry.food_id) }, primary_key: 'description', class_name: 'FoodMeasure' 
    # Or even:   ->(food_entry) { food_entry.food.measures }, etc. 
end 

將會產生這樣一個完全可以接受的查詢:

> FoodEntry.first.measure 
FoodMeasure Load (15.6ms) SELECT "food_measures".* FROM "food_measures" WHERE "food_measures"."description" = $1 AND "food_measures"."food_id" = '123' LIMIT 1 [["description", "Broccoli head"]] 

注意,這個假設measure_id在這種情況下是一個字符串列(因爲description是一個字符串)。

反觀StandardMeasure數據是我的控制之下並沒有引用Foods,所以它使得在這種情況下簡單地引用id柱完美的感覺。

所以我的問題的癥結是:我需要一種方式來使用FoodEntry來引用一種類型的度量,就像我在上面所做的多態關聯示例中那樣。但是我不知道我怎麼會實現相對於多態關聯到我的measure模型,因爲它代表:

  • 關聯FoodMeasure需要通過一個範圍內引用,而StandardMeasure沒有。
  • 關聯的FoodMeasure需要被字符串引用,而StandardMeasure被整數引用(並且被引用的列具有不同的名稱)。

如何解決這些問題?


編輯:我想我應該解釋爲什麼我不希望使用自動編號idFoodMeasures如我在FoodEntries外鍵。當數據集被更新,我的計劃是:

  1. 重命名當前food_measuresretired_food_measures(或其他)。
  2. 將新數據集導入新的food_measures表(使用一組新的自動編號ID)。
  3. 在這兩個表之間運行連接,然後刪除retired_food_measures中的任何常見記錄,因此它只包含退役記錄。

如果我引用的food_iddescription這些措施,這樣,我得到的食物條目自動指向新的記錄,因此任何更新的數值數據爲某項措施的好處。如果在新表中找不到引用的度量值,我可以指示我的應用程序在retired_food_measures表中搜索。

這就是爲什麼我認爲使用id列會使事情變得更加複雜,爲了得到我必須確保每一個更新的記錄收到了同樣的id與舊相同的好處,每一個新的紀錄接到新的未使用 - 在id之前,並且任何退役的id不再使用。

還有一個原因,我不想這樣做:排序。轉儲中的記錄首先按food_id排序,但是對於任何給定的food_id,這些度量標準都是非字母表,但仍然是我想保留的邏輯順序。 id列可以優雅地服務於此目的(因爲id在導入時按行順序分配),但是當id開始混淆時,我失去了這種好處。

所以是的,我相信我可以實施這些問題的解決方案,但我不確定這是否值得的好處?

+0

另請參見:[數據庫表的最佳設計是什麼,可以由兩個不同的資源擁有,因此需要兩個不同的外鍵?](http://stackoverflow.com/a/13317463/533120) –

回答

0

它對保持參照完整性 完好時(外部提供的)數據被更新

這是一種錯覺一個相當大的挑戰。你可以完全控制代理人。您可以完全處理外部更新,無論他們是否在那裏。

這只是當你想要自己的新名字的時候,在這種情況下,其中FoodMeasures和StandardMeasure是子類型的度量值之一。在所有三個模型/表中都有一個measure_id。你可以找到許多用於簡化子類型約束的習慣用法,例如使用類型標記。

如果您處理外部更新的方式是便於此類對象也具有此類代理,那麼您需要將此類PutativeFoodMeasures和FoodMeasures與某些超類型PutativeOrProvenFoodMeasure和/或PutativeOrProvenMeasure的子類型分開。

編輯:

您的更新幫助。你描述了我所做的。將舊的映射到新的ID並不困難;加入舊的& new(food_id,description)並選擇舊的id(不是food_id!)。你控制ID;重新使用id與它們相比如何不重要?同上FoodMeasures排序;盡你所能去做。只有當您將它們與StandardMeasures混合時纔會產生一些結果,您需要以不同的方式訂購混合物;但無論如何你都會這樣做,無論是否存在共享的ID。 (儘管「多態:」可能不是最好的ID分享設計。)

「度量」模型提供了度量;當你知道你有一個FoodMeasure或StandardMeasure時,你可以得到它的子類型特定部分。

+0

我很難解釋你的答案。你能舉一個你如何做的例子嗎? – Inkling

+0

你讀過Branko的評論鏈接了嗎?重新測量:您的衡量標準 - FoodMeasures-StandardMeasures是他的通知用戶組。 – philipxy