【问题标题】:How to change primary ID of a record in Rails?如何更改 Rails 中记录的主 ID?
【发布时间】:2011-11-28 20:04:12
【问题描述】:
导轨控制台 u = User.find(9) u.id = 7 # 没有其他id为7的记录 u.save => 真 用户.all

id 没有改变。

如何更改主ID?为什么它会阻止此操作?

在 Rails 3.0.7 和 PostgreSQL 中工作。

编辑: 既然有充分的理由不这样做,我将解释原因并希望这是一个充分的理由。

我们正在对 Staging 进行可用性测试,所以我希望它看起来像 Production 以方便每个人。我不想在可用性测试过程中造成混乱或错误,因为有些东西在暂存时按一个顺序排列,而在生产时按不同顺序排列。我在 Staging DB 上只更改了一个 PK id。

不要在您的生产数据库上执行此操作!

【问题讨论】:

标签: ruby-on-rails ruby-on-rails-3 activerecord


【解决方案1】:

我不确定它为什么会阻止该操作,但它确实会阻止它。

您可以为用户使用 update_all 方法绕过此问题。

User.where(id: 7).update_all(id: 9)

如果可能的话,你真的应该避免这样做。

【讨论】:

  • 这对我不起作用,rails 文档中提到的语法效果更好User.where(id: 7).update_all id: 9
  • ArgumentError: wrong number of arguments (given 2, expected 1) 在 Rails 4.1.16 中
【解决方案2】:

为我工作:

User.find(9).update_column(:id, 7)

【讨论】:

  • 这取决于所使用的数据库或数据库适配器。我得到了:ActiveRecord::StatementInvalid: TinyTds::Error: Cannot update identity column 'id'
【解决方案3】:

您能否详细说明您的用例是什么?为什么要换身份证?你真正想用它来完成什么?

通常这样做是个坏主意,Rails 不会让你轻易做到这一点,因为它会破坏你的数据完整性!

原因如下: 当您在下面使用关系数据库(如 PostgreSQL)时,您的模型之间会有关系,这意味着您将使用模型的 ID 作为其他相关模型的参考......这意味着如果您更改条目的 ID ,所有对该条目的引用都会过时并损坏您的数据库..

我强烈建议再次分析您的需求,并尝试找到另一种方法来完成您需要做的事情(不更改 ID)

【讨论】:

  • 感谢您的警告。我正在使我的暂存数据库看起来像生产数据库。我了解所有引用用户 ID 9 的记录都将成为孤立记录。
  • 从生产数据库中加载数据库转储怎么样?那不行吗?这将确保所有表的状态都是有效的。
  • 我不想要生产中的所有数据。我只希望用户以相同的顺序。别担心,其中只有 8 个,而且我修复了对 #9 的一个引用。
  • 哦,好的。我没有使用过 PostgreSQL ,但是在 MySQL 中你可以单独转储表——这样你可以通过部分 DB-dump 完成同样的事情(无需手动调整 ID)
  • 只有一个 ID 需要调整,所以没什么大不了的。
【解决方案4】:

@Jason 指出了一个非常有效的观点。我完全同意他的看法。但是,你可能有你的理由,我建议你重新考虑你想要做什么。

回答你的问题:

默认情况下,ID 列受批量分配保护,不能手动设置。但是,您可以通过定义一个方法来覆盖此行为:

def self.attributes_protected_by_default
  [] # ["id", ..other]
end

这将允许您手动分配 id。

【讨论】:

    【解决方案5】:

    另一种方法(虽然它不是纯 Rails)是创建一个新列,并用您的新 ID 填充它。

    然后,使用数据库管理软件(不是 Rails),从 id 列中删除 Primary Key 属性,将其删除,将您最近添加的列重命名为“id”,并为其赋予 Primary Key 属性。 (如果您不能直接在数据库软件中执行此操作,请设置属性 Unique、Auto-Increment 等)

    您也可以将列移到最前面(MySQL 语法):

    ALTER TABLE table_name MODIFY COLUMN id int(11) FIRST;
    

    但还有一件事我真的很想说。在这个问题上并没有我在其他地方看到的那么糟糕,但是伙计们:告诉人们这通常不是一个好主意,但这并不是问题的答案。请不要说“不要那样做”,除非您已经知道该人的用例。

    在其他论坛上,我对有人说“你为什么要这样做?”感到非常沮丧。或“不要那样做”,然后不回答问题。他们没有因为我已经知道这不是标准做法而给予我荣誉,他们认为我还不知道这不是一个普通的用例。

    这个页面上的人并没有那么糟糕,我也不想挑剔他们。我只是告诫:请在开始演讲之前检查自己的行为。有人问了一个问题,虽然警告可能是个好主意,但可以安全地假设他们有一个想要答案的原因。

    吐槽结束。

    【讨论】:

    • “这通常不是一个好主意” - 是的,我同意。编程中几乎没有绝对性。
    【解决方案6】:

    ID 通常由数据库生成为自动递增的 PK。你不能(而且真的不需要)修改它。

    【讨论】:

    • 哦,好吧,至少有一个很好的理由......事实证明有办法。请参阅 Olives 的回答。
    • 曾在允许您这样做的旧数据库中工作,我可以根据经验告诉您,这是一个可怕的想法。允许这样做会使破坏数据库的引用完整性变得非常简单。
    • 是的,我知道。我正在将我的暂存数据库设置为类似于生产数据库。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-01
    • 1970-01-01
    相关资源
    最近更新 更多