ActiveRecord的进口和放大器;在PostgreSQL的连载专栏 [英] Activerecord-import & serial column in PostgreSQL
问题描述
我在升级的Rails 2.3.4项目到Rails 3.1.1的过程。旧版本中使用AR-扩展处理数据导入。我掏出AR-扩展和与ActiveRecord的进口,这点我明白了完全相同的接口。
I am in the process of upgrading a Rails 2.3.4 project to Rails 3.1.1. The old version used ar-extensions to handle a data import. I pulled out ar-extensions and replaced it with activerecord-import, which I understand has exactly the same interfaces.
我的code调用看起来像这样
My code calls looks like this
Student.import(columns, values)
两者的args是保持正确的数据有效阵列,但我得到一个大胖子的错误!
Both args are valid arrays holding the correct data, but I get a big fat error!
错误堆栈看起来是这样的:
The error stack looks like this:
NoMethodError (You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.split):
activerecord (3.1.1) lib/active_record/connection_adapters/postgresql_adapter.rb:828:in 'default_sequence_name'
activerecord (3.1.1) lib/active_record/base.rb:647:in `reset_sequence_name'
activerecord (3.1.1) lib/active_record/base.rb:643:in `sequence_name'
activerecord-import (0.2.9) lib/activerecord-import/import.rb:203:in `import'
翻翻code却仿佛ActiveRecord的进口要求的ActiveRecord从而查找名称和Postgres的序列的下一个值。
Looking through the code it seems as though Activerecord-import calls activerecord which in turn looks for the name and next value of the Postgres sequence.
所以ActiveRecord的导入查找SEQUENCE_NAME LIB / ActiveRecord的导入/ import.rb:203
So activerecord-import looks for the sequence_name lib/activerecord-import/import.rb:203
# Force the primary key col into the insert if it's not
# on the list and we are using a sequence and stuff a nil
# value for it into each row so the sequencer will fire later
-> if !column_names.include?(primary_key) && sequence_name && connection.prefetch_primary_key?
column_names << primary_key
array_of_attributes.each { |a| a << nil }
end
它调用活动记录... LIB / active_record / base.rb:647:在'reset_sequence_name
It calls active record ... lib/active_record/base.rb:647:in `reset_sequence_name'
# Lazy-set the sequence name to the connection's default. This method
# is only ever called once since set_sequence_name overrides it.
def sequence_name #:nodoc:
-> reset_sequence_name
end
def reset_sequence_name #:nodoc:
-> default = connection.default_sequence_name(table_name, primary_key)
set_sequence_name(default)
default
end
在 serial_sequence
返回nil和 default_sequence_name
试图拆分它。
The code errors when serial_sequence
returns nil and default_sequence_name
tries to split it.
lib/active_record/connection_adapters/postgresql_adapter.rb
# Returns the sequence name for a table's primary key or some other specified key.
def default_sequence_name(table_name, pk = nil) #:nodoc:
-> serial_sequence(table_name, pk || 'id').split('.').last
rescue ActiveRecord::StatementInvalid
"#{table_name}_#{pk || 'id'}_seq"
end
def serial_sequence(table, column)
result = exec_query(<<-eosql, 'SCHEMA', [[nil, table], [nil, column]])
SELECT pg_get_serial_sequence($1, $2)
eosql
result.rows.first.first
end
当我执行 pg_get_serial_sequence()
直接对我没有得到任何返回值的数据库:
When I execute pg_get_serial_sequence()
directly against the database I get no value returned:
SELECT pg_get_serial_sequence('student', 'id')
不过,我可以看到,在数据库中有一个序列名为 student_id_seq
我使用的红宝石以下版本,轨道PG等。
I am using the following versions of Ruby, rails PG etc..
- 的Rails 3.1.1
- 的Ruby 1.9.2
- ActiveRecord的进口0.2.9
- 第0.12.2提供
- 在PSQL(9.0.5,9.1.3服务器)
我已经迁移的数据库从MySQL到PostgreSQL,我不认为这对问题有任何影响,但我认为我最好添加它的完整性。
I have migrated the database from MySQL to PostgreSQL, I don't think this has any bearing on the problem but I thought that I'd better add it for completeness.
我不明白为什么这是行不通的!
I can't work out why this isn't working!
推荐答案
- 表
学生
的存在。 - 在列
ID
的存在。 - 顺序
student_id_seq
的存在。 -
pg_get_serial_sequence('学生','ID')
仍返回NULL
。
Summary of your description:
- The table
student
exists. - The column
id
exists. - The sequence
student_id_seq
exists. pg_get_serial_sequence('student', 'id')
still returnsNULL
.
1)顺序为不挂以列。
默认列与列和序列之间的联系是独立的功能。仅仅存在一个合适的顺序并不意味着它做什么,你presume。如果您创建一个列系列
你全包,但。阅读在手动的细节。
Column default and the tie between column and sequence are independent features. The mere existence of a fitting sequence does not mean it does what you presume. If you create a column as serial
you get the whole package, though. Read the details in the manual.
要解决这个问题(如果你确信这是应该的),你可以标记的顺序为归 student.id
:
To fix this (and if you are sure that's how it should be), you can mark the sequence as "owned by" student.id
:
ALTER SEQUENCE student_id_seq OWNED BY student.id;
另外检查列默认设置为预期的:
Also check if the column default is set as expected:
SELECT column_name, column_default
FROM information_schema.columns
WHERE table_name = 'student'
-- AND schema = 'your_schema' -- if needed
如果没有,修:
ALTER TABLE student ALTER COLUMN id SET DEFAULT nextval('student.id')
2)的的mixup 表名的主机地址/端口/数据库/模式/资本化。
2) A mixup of host address / port / database / schema / capitalization of the table name.
这一切发生的时间。请确保您检查您的应用程序连接到同一个数据库,使用相同的用户或者至少是相同的 SEARCH_PATH
。确保的对象是在你所期望的模式并没有,比如,另一个学生
表中的搞混了另一种模式。
It happens all the time. Make sure you check the same database that your app connects to, With the same user or at least the same search_path
. Make sure, the objects are in the schema where you expect them and there isn't, for instance, another student
table in another schema that got mixed up.
这篇关于ActiveRecord的进口和放大器;在PostgreSQL的连载专栏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!