我有一个模型,可以使用 pg
gem 将数据直接加载到数据库中。它通过动态创建 CSV 文件并通过调用将值分配给 id
字段来实现此目的:
self.class.select("nextval('apps_id_seq'::regclass)").first['nextval']
在 to_csv
实例方法中。
这在生产中效果很好。但是,我正在填写一些测试,如果首先运行此测试,或者单独运行此测试,它会失败,因为数据库刚刚被数据库清理器 gem 和序列重置被重置。但它们没有给出起始值。
Postgres 文档说您可以对相关序列调用 setval
来进行设置。假设我想将其设置为从 1 开始,以便下次调用 nextval
时,它将返回 1:
select setval('apps_id_seq'::regclass, 1, false);
但我不能像上面调用 nextval
那样调用它,因为它根本不起作用。它返回 nil,并且不设置序列。
我尝试过的任何事情都没有迭代:
self.class.select("setval('apps_id_seq'::regclass)").first
App.connection.execute("select setval('apps_id_seq'::regclass,1,false)")
ActiveRecord::Base.connection.execute("select setval('apps_id_seq'::regclass,1)")
ActiveRecord::Base.connection.execute("select setval('apps_id_seq'::regclass,1,false)")
ActiveRecord::Base.connection.execute("select setval('apps_id_seq'::regclass,1,false)")
它们的任何组合都不起作用,它只是拒绝
起作用。我不知道这是否是 pg
gem 问题。
更新
这些语句在开发
模式下工作:
App.select("setval('apps_id_seq'::regclass,1)").first
和:
App.select("nextval('apps_id_seq'::regclass)").first
然而,它们在测试
中都不起作用。
但是,这些语句确实可以在测试
模式下工作:
ActiveRecord::Base.connection.execute("select setval('apps_id_seq'::regclass,1,false)").first
和:
ActiveRecord::Base.connection.execute("select nextval('apps_id_seq'::regclass)").first
据我所知,这两种环境中的唯一区别是一种环境有数据,而另一种环境没有数据。我的测试数据库是使用 rake db:test:prepare
从 structure.sql
文件创建的。
最佳答案
无论序列附加到的表中是否有数据,
setval
和 nextval
都会起作用。序列可以被创建和递增,甚至无需与现有表的列相关联。当您使用 Model.select 执行原始 SQL 时,ActiveRecord 会为您正在使用的模型的表生成带有 from 子句的 SQL:
> App.select("setval('apps_id_seq'::regclass,1)").first
SELECT nextval('apps_id_seq'::regclass)
FROM "apps" ORDER BY "apps"."id" ASC LIMIT 1'
=> nil
因为apps表中没有记录,所以setval函数永远不会被执行。这就是为什么直接使用连接时相同的选择可以工作,因为选择没有无关的 from 子句:
> ActiveRecord::Base.connection.execute("SELECT setval('apps_id_seq'::regclass, 1)").first
SELECT setval('apps_id_seq'::regclass, 1)
=> {"setval"=>"1"}
使用此形式执行 SQL,以便确保始终对 setval
函数进行求值。
关于ruby-on-rails-3 - 对于 Rails 3.2.16 中的 Postgres,序列 "setval"操作与 "nextval"的工作方式不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21146760/