【问题标题】:Rails auto-assigning id that already existsRails 自动分配已经存在的 id
【发布时间】:2012-06-19 14:14:48
【问题描述】:

我像这样创建一个新记录:

truck = Truck.create(:name=>name, :user_id=>2)

我的数据库目前有数千个卡车实体,但我将 id 分配给了其中几个实体,以某种方式留下了一些可用的 id。所以发生的事情是 rails 创建了 id = 150 的项目,它工作正常。但随后它尝试创建一个项目并为其分配 id = 151,但该 id 可能已经存在,所以我看到了这个错误:

ActiveRecord::RecordNotUnique (PG::Error: ERROR: duplicate key value violates unique constraint "companies_pkey" DETAIL: Key (id)=(151) already exists.

下次我运行该操作时,它会简单地分配 id 152,如果尚未采用该值,它将正常工作。如何让 rails 在分配 ID 之前检查它是否已经存在?

谢谢!

编辑

卡车 id 是被复制的。用户已经存在并且在这种情况下是一个常量。这实际上是我必须处理的遗留问题。一种选择是,这次在 let rails auto assign each id 时重新创建表。我开始认为这可能是最好的选择,因为我还有其他一些问题,但是这样做的迁移会非常复杂,因为 Truck 是许多其他表中的外键。是否有一种简单的方法让 rails 使用已存储在 Truck 下的相同数据创建一个新表,并使用自动分配的 ID 并维护所有现有关系?

【问题讨论】:

  • 为什么不让 rails 自动分配 ID?这将消除任何重复的危险——或者这是您必须保留旧 ID 的遗留数据问题?只是想稍微了解一下业务案例,因为在创建新对象时这并不像往常一样。
  • @MBHNYC 我认为 D-Nice 在创建公司时分配了一个 user_id,而不是你想的 id(我也做了一会儿)。
  • 太好了,阿尼尔——你完全正确。 @D-Nice,也许将此表的迁移添加到您的帖子中,以防有什么奇怪的地方?很想编辑掉那个 user_id 以消除混乱..
  • 不,抱歉不清楚,公司 ID 是被复制的。用户已经存在并且在这种情况下是一个常量。这实际上是我必须处理的遗留问题。将使用更多信息编辑帖子
  • 您不需要重新创建表。只需查看我的答案即可重置序列。

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


【解决方案1】:

听起来像是数据库问题,而不是 Rails 问题。您的数据库是否有可能在您的 id 列上有不正确的身份种子?要进行测试,请尝试直接在数据库中插入几次,看看是否存在相同的行为。

【讨论】:

  • 为什么投反对票?如果您将增量序列设置为低于其他现有值的值,因此在插入数据时偶尔会发生冲突,这就是发生的确切行为。发帖人已经说过有属于这种情况的现有数据。
  • 我可以正常插入。在我收到此错误后,如果序列中的下一个 id 尚未被采用,我实际上可以再次运行相同的操作并让它工作。
  • 似乎这是我的情况——我遇到了问题,但我插入的下一条记录工作正常,所以它一定把种子放在了正确的位置。
【解决方案2】:

Rails 可能正在使用内置的 PostgreSQL 序列。序列的思想是它只使用一次。

最简单的解决方案是使用如下查询将 company.id 列的序列设置为表中的最大值:

SELECT setval('company_id_seq', (SELECT max(id) FROM company));

我猜你的序列名“company_id_seq”、表名“company”和列名“id”……请用正确的替换它们。您可以使用SELECT pg_get_serial_sequence('tablename', 'columname'); 获取序列名称或使用\d tablename 查看表定义。

另一种解决方案是覆盖公司类中的 save() 方法,以便在保存之前手动设置新行的公司 ID。

【讨论】:

  • 我猜那会做的是从当前最高值 + 1 开始自动分配?
  • 我认为这是对我的问题的最佳答案,但是,由于不相关的原因,我将不得不找到一种方法来使用我在我的 OP 编辑​​中描述的策略
  • 我不明白为什么会发生这种情况?这发生在我身上,我想知道这怎么可能。
  • @Websitescenes,如果在 PostgreSQL 中有一个 SERIAL 列(串行列是其中默认值是序列中的下一个值的列),则用该列中的硬值填充表,序列不会自动更新。示例:create table t (id serial not null primary key); insert into t values (1); insert into t values (default); ERROR: duplicate key value violates unique constraint "t_pkey" DETAIL: Key (id)=(1) already exists.
【解决方案3】:

我这样做为我解决了这个问题。

ActiveRecord::Base.connection.tables.each do |t|
  ActiveRecord::Base.connection.reset_pk_sequence!(t)
end

我找到了reset_pk_sequence!从这个线程。 http://www.ruby-forum.com/topic/64428

【讨论】:

  • 谢谢,最好的解决方案。数据库传输后,我遇到了同样的问题。
  • 或单行等效项(用于 Rails 控制台复制/粘贴目的):ActiveRecord::Base.connection.tables.each { |t| ActiveRecord::Base.connection.reset_pk_sequence!(t) }
  • 知道这是如何不同步的吗?
【解决方案4】:

基于@Apie answer

您可以创建一个任务并在需要时运行:

rake database:correction_seq_id

你创建这样的任务:

rails g task database correction_seq_id

并在生成的文件中(lib/tasks/database.rake)放:

namespace :database do
    desc "Correction of sequences id"
    task correction_seq_id: :environment do
        ActiveRecord::Base.connection.tables.each do |t|
            ActiveRecord::Base.connection.reset_pk_sequence!(t)
        end
    end
end

【讨论】:

    【解决方案5】:

    我通过以下命令解决了这个问题。

    在你的 Rails 控制台中运行它

    ActiveRecord::Base.connection.reset_pk_sequence!('table_name')
    

    【讨论】:

      猜你喜欢
      • 2017-07-21
      • 2014-04-15
      • 1970-01-01
      • 2016-05-02
      • 2017-12-05
      • 1970-01-01
      • 2020-02-11
      • 2019-04-27
      • 1970-01-01
      相关资源
      最近更新 更多