くまきち

山と旅と家族が大事。
でも激しい物欲が理性と財布のタガを飛ばす
最近は自転車も乗ってる

テーブルの継承

2012-01-24 17:11:20 | SEまわり
とあるツールを作ろうとしてクラス図を描いたはいいが、継承の親子関係にあるクラスそれぞれをテーブルに結びつけるってできるのか? と疑問に思った。

これまでは、現実世界からクラス図に落とし込むときに、テーブルも作りやすいように描いてきたけど、今回はそのクラスの数が今までよりもかなり多くなってきて、ややこしいから、できれば1クラス1テーブルになってくるととてもありがたいわけだ。

幸い、データベースは PostgreSQL なのでテーブルの継承機能がある。

が、今まで実用で使ったことがなかったので、試してみた。


まず、単純に親テーブル(items)と子テーブル(servers)を作る。

create table items ( id serial, name varchar(10), primary key(id));
create table servers ( typename varchar(10), primary key(id));


んでもって、items テーブルにデータを入れてみる。これは問題ない。

test=# insert into items ( name ) values ('logger'), ('dns');
INSERT 0 2


次に、子テーブルの servers にデータを入れてみる。 入れたあとに、items テーブルにもデータが入っていたら期待通りの動作。

test=# insert into servers ( name, typename ) values ('mail', 'RX78'), ('web', 'PC-8001');
INSERT 0 2
test=# select * from servers;
id | name | typename
----+------+----------
4 | mail | RX78
5 | web | PC-8001
(2 rows)

test=# select * from items;
id | name
----+--------
2 | logger
3 | dns
4 | mail
5 | web
(4 rows)


できてる。

また、servers をさらに継承した hpcservers を作ってみたが、こちらも問題なかった。

ということで、イケるのは分かった。

ただ、上記のテーブル定義だと、孫テーブルで speed だけ指定しても通ってしまうので、まじめに制約を含めて作り直した。

NOTICE: CREATE TABLE will create implicit sequence "items_id_seq" for serial column "items.id"
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "items_pkey" for table "items"
NOTICE: CREATE TABLE / UNIQUE will create implicit index "items_name_key" for table "items"
CREATE TABLE
test=# create table servers ( typename varchar(10) not null, primary key(id)) inherits (items);
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "servers_pkey" for table "servers"
CREATE TABLE
test=# create table hpcservers ( speed int ) inherits (servers);
CREATE TABLE


で、データを入れてから確認してみた。

test=# insert into hpcservers ( speed ) values (10);
ERROR: null value in column "name" violates not-null constraint
test=# insert into hpcservers ( name, speed ) values ('RX78', 10);
ERROR: null value in column "typename" violates not-null constraint
test=# insert into hpcservers ( name, typename, speed ) values ('logger', 'RX78', 10);
INSERT 0 1
test=# select * from hpcservers;
id | name | typename | speed
----+--------+----------+-------
3 | logger | RX78 | 10
(1 row)

test=# select * from servers;
id | name | typename
----+--------+----------
3 | logger | RX78
(1 row)

test=# select * from items;
id | name
----+--------
3 | logger
(1 row)


期待通りの動きですね。

子や孫テーブルの定義(psql 対話インタフェースにて \d servers とか)を見ると、ちゃんと親から引き継いだカラムも含まれているから、CakePHP ではそのまま意識せずに bake しても大丈夫なんじゃないかと思う。

というわけで、安心して設計を進める。


ただ、ER図には継承/汎化を表現する記号がない(と思う)ので、クラス図上でなるべくプロパティを丁寧に書いて、そこから最終的に SQL に落とし込むことになるかな。

最新の画像もっと見る