我有一个模型,可以使用pg
gem将数据直接加载到数据库。它通过动态创建CSV文件并通过调用以下内容将值分配给id
字段来实现此目的:
self.class.select("nextval('apps_id_seq'::regclass)").first['nextval']
在to_csv
实例方法中。
这在生产中很有效。但是,我正在填写一些测试,如果这个测试首先运行,或者单独运行,它会失败,因为数据库刚刚被Database Cleaner
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)")
也没有任何组合起作用,只需refuses
即可。我不知道这是否是pg
宝石问题。
的更新 的
这些陈述适用于development
模式:
App.select("setval('apps_id_seq'::regclass,1)").first
和
App.select("nextval('apps_id_seq'::regclass)").first
然而,它们都不适用于test
。
但是,这些陈述在test
模式下有效:
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
创建的。
答案 0 :(得分:2)
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函数。这就是为什么同一个select在直接使用连接时有效,因为select没有多余的from子句:
> ActiveRecord::Base.connection.execute("SELECT setval('apps_id_seq'::regclass, 1)").first
SELECT setval('apps_id_seq'::regclass, 1)
=> {"setval"=>"1"}
使用此表单执行SQL,以确保始终评估setval
函数。