DBIx::Class + Oracle でプライマリーキーを auto increment する方法
Oracle には、MySQL の auto_increment 属性に該当する機能がありません。実現するには、次のサイトで紹介されているように、SEQUENCE と TRIGGER を組み合わせるというのが常套手段のようです。
でも、Perl の DBIx::Class を使えばラクチンです!例えば、次のようなクラスを作ったとします。
MyApp/Schema/Result/Post.pm
use strict;
use warnings;
use base 'DBIx::Class';
__PACKAGE__->load_components( "Core" );
__PACKAGE__->table("post");
__PACKAGE__->add_columns(
id => {
data_type => 'NUMBER',
size => 11,
is_nullable => 0,
is_auto_increment => 1,
},
title => {
data_type => 'VARCHAR2',
size => 500,
},
);
__PACKAGE__->set_primary_key("id");
1;
15行目で is_auto_increment => 1 という指定をしています。この状態で、DBIx::Class::Schema の deploy メソッドを実行すると、次のように TABLE と同時に SEQUENCE と TRIGGER を自動的に作成してくれます。
CREATE TABLE post (
id number(11) NOT NULL,
title varchar2(500),
PRIMARY KEY (id)
);
CREATE OR REPLACE TRIGGER ai_post_id
BEFORE INSERT ON post
FOR EACH ROW WHEN (
new.id IS NULL OR new.id = 0
)
BEGIN
SELECT sq_post_id.NEXTVAL
INTO :new.id
FROM dual;
END;
実際の処理は、SQL::Translator::Producer::Oracle が担当しているようです。
ちなみに、add_columns() でカラムを定義する時に、data_type => ‘timestamp’ とすると、同様に次のような TRIGGER が作成され、レコードの追加および更新時に自動的に SYSDATE をセットしてくれます。
BEFORE INSERT OR UPDATE ON post
FOR EACH ROW WHEN (new.updated_at IS NULL)
BEGIN
SELECT sysdate INTO :new.updated_at FROM dual;
END;
仕事で Oracle を使うことになり、「えー!auto_increment ないのー!」と困っていたのですが、おかげで楽に実装できました。欲を言えば、作成する SEQUENCE の START WITH を指定できたり、レコードの追加のときだけ SYSDATE をセットしてくれる TRIGGER が自動生成できれば、もっとありがたいんだけどなぁ。
About this entry







No Trackbacks
trackback uri:コメントやトラックバックは承認待ちになる場合がありますので、すぐに反映されない場合はしばらくお待ちください。