Ruby on rails Rails行为异常wrt Postgres SERIAL NOT NULL列
我正在开发一个(目前)Rails 2.3.x应用程序,它有一个PostgreSQL 8.4数据库后端。在我的Rails应用程序中,我有一个与数据库表相对应的模型,该数据库表有两列数据类型SERIAL,并设置为NOTNULL。我将其中一列设置为Rails中的主键和PostgreSQL约束 表定义:Ruby on rails Rails行为异常wrt Postgres SERIAL NOT NULL列,ruby-on-rails,postgresql,ruby-on-rails-3,plpgsql,Ruby On Rails,Postgresql,Ruby On Rails 3,Plpgsql,我正在开发一个(目前)Rails 2.3.x应用程序,它有一个PostgreSQL 8.4数据库后端。在我的Rails应用程序中,我有一个与数据库表相对应的模型,该数据库表有两列数据类型SERIAL,并设置为NOTNULL。我将其中一列设置为Rails中的主键和PostgreSQL约束 表定义: CREATE TABLE problem_table ( col1 serial NOT NULL, col2 serial NOT NULL, other_col1 character v
CREATE TABLE problem_table
(
col1 serial NOT NULL,
col2 serial NOT NULL,
other_col1 character varying,
other_col2 character varying,
...,
CONSTRAINT problem_table_pkey PRIMARY KEY (col1)
);
class ModelClass1 < ActiveRecord::Base
self.table_name = 'problem_table'
self.primary_key = 'col1'
end
模型类定义:
CREATE TABLE problem_table
(
col1 serial NOT NULL,
col2 serial NOT NULL,
other_col1 character varying,
other_col2 character varying,
...,
CONSTRAINT problem_table_pkey PRIMARY KEY (col1)
);
class ModelClass1 < ActiveRecord::Base
self.table_name = 'problem_table'
self.primary_key = 'col1'
end
Rails告诉PostgreSQL的是:
INSERT INTO problem_table (
col2,
other_col1,
other_col2,
...
) VALUES (
NULL,
'normal',
'data',
...
);
我的问题是,如何让Rails停止为此列传递NULL而不传递任何内容,让默认的nextval(My_seq)接管?或者,如果不可能,我如何告诉PostgreSQL在传递时忽略此空值和/或识别此空值与“设为默认值”相同
我会尝试对Rails 2.3.x ActiveRecord内部进行修补,但我知道如果我这样做了,那么在过渡到Rails 3时,我会被搞砸
我已经研究过如何在插入之前使用PL/pgSQL触发器修复问题,但我不知道如何让带有PL/pgSQL的PostgreSQL“取消定义”NEW.col2值或说NEW.col2:=DEFAULT(这不起作用)
感谢您的回答和/或建议 不确定PL/pgSQL语法的精确性(我的PostgreSQL安装在家里,所以我不能玩弄它),但在Oracle PL/SQL中,我会这样做
CREATE OR REPLACE TRIGGER MYSCHEMA.PROBLEM_TABLE_BI
BEFORE INSERT ON MYSCHEMA.PROBLEM_TABLE
REFERENCING NEW AS NEW
FOR EACH ROW
BEGIN
IF :NEW.COL2 IS NULL THEN
:NEW.COL2 := MY_SEQ.NEXT_VAL;
END IF;
END PROBLEM_TABLE_BI;
PL/pgSQL应该是类似的
希望这有帮助。找到了一些有效的方法。我可能需要在相当多的表中使用第二个串行列,这些表使用不同的递增序列。下面是一个解决方案,其中包含按唯一序列递增的col1的任意数量的表只需要1个触发器函数
CREATE OR REPLACE FUNCTION fn_set_col1_as_nextval_sequence_if_null()
RETURNS trigger AS
$BODY$
BEGIN
IF NEW.col1 IS NULL THEN
SELECT nextval(TG_ARGV[0]) INTO NEW.col1;
END IF;
RETURN NEW;
END;
$BODY$
LANGUAGE 'plpgsql';
CREATE TRIGGER trg_set_col1_as_nextval_sequence_on_problem_table_create
BEFORE INSERT
ON problem_table
FOR EACH ROW
EXECUTE PROCEDURE fn_set_col1_as_nextval_sequence_if_null('problem_table_col1_seq');
如果可能的话,我仍然想弄清楚如何修复2.3.x和3.0的Rails行为,但这将同时起作用。更简单的方法可能是定义自己的序列,并在ActiveRecord回调中使用Postgres自己的
nextval()
nextval()
在一个原子操作中处理将序列向前推进一步和返回下一个值
在迁移过程中:
def self.up
execute "CREATE SEQUENCE myseq"
end
def self.down
execute "DROP SEQUENCE myseq"
end
在模型中:
before_save :set_column_from_sequence, :on => :create
def set_column_from_sequence
self.mycolumn = self.class.connection.select_value("SELECT nextval('myseq')")
end
谢谢我现在有了一个基于这个策略的东西@克里斯戈达德——这就是生活。:-}谢谢你!rails 2.3到3.1升级期间的巨大帮助