0

小问题......这是为了解决什么是简单的黑客攻击,不修复似乎很愚蠢!

如果有两个来自 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!
4

2 回答 2

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. 之后,您将需要具有10 和 20reload的模型实例。id

编写一个交换两个数据库行的主键的 SQL 语句会有点棘手(但是可能,取决于您的数据库服务器)。但是 ActiveRecord 不会帮助你。

你为什么需要那个?这个问题看起来很奇怪,所以我猜你实际上需要别的东西。

于 2013-05-30T23:46:30.517 回答
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;
于 2013-05-31T05:40:36.833 回答