【问题标题】:Rails + postgres autoincrement not updated on explicit id insertsRails + postgres 自动增量未在显式 id 插入时更新
【发布时间】:2014-11-06 22:45:06
【问题描述】:

我遇到了同样的问题post。但我正在使用 Rails,不知道如何在 activerecord 中解决此问题。

我正在使用 seed.rb 插入一些数据:

device_platforms = DevicePlatform.create([{id: 1, name: 'Android'}, {id: 2, name: 'IOS'}, {id: 3, name: 'Windows Phone'}])

当我插入另一个 DevicePlatform 时,我得到了这个异常:

Failure/Error: @device_platform = FactoryGirl.create(:device_platform)
 ActiveRecord::RecordNotUnique:
   PG::UniqueViolation: ERRO:  duplicar valor da chave viola a restrição de unicidade "device_platforms_pkey"                                                                 
   DETAIL:  Chave (id)=(2) já existe.
   : INSERT INTO "device_platforms" ("created_at", "name", "updated_at") VALUES ($1, $2, $3) RETURNING "id"        

消息是葡萄牙语,它表示具有该 ID 的行已经存在。

谢谢。

【问题讨论】:

  • 为什么要指定 id?
  • 不要在种子中包含ids。如果您必须在种子中包含ids,那么您必须在添加种子后在另一个问题中使用connection.execute SQL。
  • 感谢您提供错误的确切文本。如果可以的话,我会 +100。
  • @muistooshort 您认为在种子文件中包含 id 是一种不好的做法?
  • 依赖于ids 是任何特别的东西是一种不好的做法。如果需要,您可以这样做,但您需要运行一些 SQL 来修补用于提供 id 值的序列。

标签: ruby-on-rails postgresql activerecord


【解决方案1】:

我相信虽然这是一个坏习惯,但很多时候它是唯一的手段

你可以定义这个方法:

def fix_self_increment(model)
  ActiveRecord::Base.connection.execute(
    "BEGIN; " \
    "LOCK TABLE #{model.table_name} IN EXCLUSIVE MODE; " \
    "SELECT setval('#{model.table_name}_id_seq', COALESCE((SELECT MAX(id)+1 FROM #{model.table_name}), 1), false); " \
    "COMMIT;"
  )
end 

然后调用

fix_self_increment(DevicePlatform)

享受

【讨论】:

  • 我会将此代码放在执行此类插入的每次数据迁移中,而不是使用执行此操作的方法。它很快就会告诉你指定 id 是个坏主意。顺便说一句,这是正确的答案。
【解决方案2】:

根据 cmets,在种子中使用 id 是一种不好的做法。我正在避免不良做法,这对我来说已经足够了。更改了我的代码以避免这种情况。

【讨论】:

  • 仍有可能发生这种情况的有效用例(例如,在您的 rake 任务中读取 CSV 文件),因此很高兴看到如何解决此问题的有效答案。
  • 请接受上面的答案,因为它确实回答了您提出的问题,即使这是一个坏主意。有时做坏事是必要的。
猜你喜欢
  • 2012-02-24
  • 1970-01-01
  • 1970-01-01
  • 2012-02-01
  • 2014-08-10
  • 2016-12-18
  • 2019-09-09
  • 1970-01-01
相关资源
最近更新 更多