已存在的Rails自动分配ID


92

我像这样创建新记录:

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

我的数据库目前有数千个用于卡车的实体,但是我以一些可用的方式将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,如果尚未使用该值,它将正常工作。如何在分配ID之前让Rails检查ID是否已经存在?

谢谢!

编辑

卡车ID是要复制的内容。用户已经存在,并且在这种情况下为常数。实际上,这是我必须处理的遗留问题。一种选择是在此时让轨道自动分配每个id的位置重新创建表。我开始认为这可能是最好的选择,因为我还有其他一些问题,但是这样做的迁移将非常复杂,因为Truck是许多其他表中的外键。有没有一种简单的方法可以让Rails使用已经在Truck下存储的相同数据,使用自动分配的ID并维护所有现有关系来创建新表?


为什么不让Rails自动分配ID?那将消除任何重复的危险-还是这是旧数据问题,您必须保留旧ID?只是想稍微了解一下业务案例,因为在创建新对象时这不是日常工作。
MBHNYC 2012年

@MBHNYC我认为D-Nice在创建公司时正在分配user_id,而不是您所想的id(我也做了一会)。
阿尼尔(Annil)2012年

噢,好抓住Anil-您完全正确。@ D-Nice,如果有奇怪的地方,也许将您对该表的迁移添加到您的帖子中?诱人的编辑指出,USER_ID,以消除混乱..
MBHNYC

不,对不起,不清楚,公司ID是重复的内容。用户已经存在,并且在这种情况下为常数。实际上,这是我必须处理的遗留问题。将编辑带有更多信息的帖子
D-Nice

您无需重新创建表。请看我的答案以重设序列。
Dondi Michael Stroma 2012年

Answers:


87

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开始吗?
D-Nice

我认为这是对我问题的最佳答案,但是,出于不相关的原因,我将必须找到一种方法来使用我在OP编辑中描述的策略
D-Nice

我不明白为什么会这样呢?这发生在我身上,我想了解这是怎么可能的。
亨特·伯迪克

2
@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.
Dondi Michael Stroma

204

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

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


4
谢谢,最好的解决方案。数据库传输后,我遇到了同样的问题。
Oleg Pasko 2013年

61
或单线等效文件(用于Rails Console复制/粘贴目的):ActiveRecord::Base.connection.tables.each { |t| ActiveRecord::Base.connection.reset_pk_sequence!(t) }
Raf

知道这怎么不同步吗?
高保罗

25

基于@Apie 答案

您可以使用以下命令制作任务并在需要时运行:

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

4

在我看来,这听起来像数据库问题,而不是Rails问题。您的数据库是否可能在您的id列上使用了不合适的身份种子?要进行测试,请尝试将几个插入直接插入到数据库中,看看是否存在相同的行为。


3
为什么要下票?如果将增量序列设置为比其他现有值低的值,因此插入数据时偶尔会发生冲突,这就是发生的确切行为。张贴者已经说过,已有数据属于这种情况。
mynameiscoffey 2012年

我可以插入。收到此错误后,如果尚未使用序列中的下一个ID,则实际上我可以再次运行相同的操作并使它工作。
D-Nice

看来这就是我的情况-我遇到了问题,但是我插入的下一个记录运行良好,因此它一定已将种子放入正确的位置。
本·惠勒2014年

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.