2013-05-30 30 views
0

小問題......這是解決什麼是簡單的破解,似乎愚蠢不能修復!Ruby - 交換兩個ActiveRecord實例的主鍵?優雅

如果從ActiveRecord派生的同一類有兩個項目,我如何交換他們的主鍵?下面的代碼工作,但看看它!

class Item < ActiveRecord::Base 
    self.primary_keys = :p_key 

    def self.swap(a, b) 
    return if a.nil? or a.nil? 

    # fix this hack! 
    temp_1 = a.p_key 
    a.p_key = "999999" #these keys cannot ever occur in our software... promise! 
    a.p_key.save! 
    a.p_key = b.p_key 
    b.p_key = temp_2 
    b.save! 
    a.save! 
    end 
end 

呃!這是毛病!

下面的代碼將導致一個錯誤:

a.p_key, b.p_key = b.p_key, a.p_key 
a.save! 
b.save! 
+0

在更高的層次上,你想要做什麼? – eabraham

回答

0

ActiveRecord的(像任何其他ORM)不允許改變主鍵。如果你以某種方式改變它,你的模型實例將引用一個不同的數據庫記錄(如果存在的話)。

例如,假設您有一個具有主鍵10的Item模型實例。如果更改任何字段並保存該模型,ActiveRecord將生成一條SQL語句,如UPDATE ... SET ... WHERE id = 10。該語句將更新id = 10的數據庫行。

如果您以某種方式將主鍵更改爲20,那麼ActiveRecord將生成一條SQL語句,如UPDATE ... SET ... WHERE id = 20。該語句更新一個不同的行(如果存在),保持id = 10的行不變。

要更改主鍵,您必須執行如下所示的SQL語句:UPDATE my_table SET id = 20 WHERE id = 10。之後,您將需要reload您的模型實例具有id 10和20.

編寫SQL語句將交換兩個數據庫行的主鍵將會有點棘手(但可能取決於您的數據庫服務器) 。但ActiveRecord不會幫助你。

爲什麼你需要那個?這個問題看起來很奇怪,所以我猜你實際上需要別的東西。

0

假設你想交換鍵值1和2標準SQL:

UPDATE tbl SET keycol = CASE keycol WHEN 1 THEN 2 WHEN 2 THEN 1 END 
WHERE keycol IN (1,2); 

你也可以解決這個問題的另一種方式和交換每非關鍵列的值 - 其中最終當然也有同樣的效果。這是一種方法,但不幸的是它不是標準的SQL。它適用於SQL Server和其他可能的,但我沒有在其他地方進行測試。要在標準SQL中實現同樣的事情,我認爲你必須創建一個視圖來代替派生表子查詢。

UPDATE t SET x1 = x2, y1 = y2, z1 = z2 
FROM 
(
    SELECT t1.keycol keycol1, t2.keycol keycol2, 
    t1.x x1, t1.y y1, t1.z z1, t2.x x2, t2.y y2, t2.z z2 
    FROM tbl t1, tbl t2 
    WHERE (t1.keycol = 1 AND t2.keycol = 2) 
    OR (t1.keycol = 2 AND t2.keycol = 1) 
) t;