« ドメインの階層化とDSP | トップページ | モデル駆動開発勉強会(4/25@東京)で語ります »

2015.04.06

「フィールドの更新不可制約」の必要性

 意識されることが少ないが、「更新不可制約」はRDBを扱う場合に配慮すべき基本事項である。ところが、そのための機構が一般のRDBMSでは手薄であるゆえに、更新不可に関する制御は開発者、または開発基盤に委ねられる。その際の考慮点を説明しよう。

 まず、更新不可制約がどのようなものかをおさらいしておこう。一義的には、「PK(一次識別子)の値は更新されてはいけない」くらいの意味である。更新できてしまえば、データの不整合が生じるからだ。たとえば、顧客のPKである顧客IDを"256"から"123"に更新できてしまえば、"256"を顧客IDとしているさまざまなテーブルレコードとの間で簡単に不整合が生じてしまう。まあ、当たり前の話である。

 ここで取り上げたいのは、「サロゲートキー」を導入した場合に要請される「属性フィールド(PKでないフィールド)の更新不可制約」である。たとえば、Ruby on Railsのような複合主キーを許さないフレームワーク(*1)を使う想定で、「倉庫在庫テーブル」が次のように設計されたとする。

[倉庫在庫]{在庫ID},...現在庫数,{倉庫ID,商品ID}

 PKとして「在庫ID」が置かれるいっぽう、「倉庫ID」と「商品ID」の組み合わせに対してユニーク制約が盛り込まれている。本来であれば{倉庫ID,商品ID}をPKとすべきなのだが、複合主キーが許されない開発環境であればこのように設計せざるを得ない。

 この場合、本来のPKであった倉庫IDと商品IDについては、レコードが追加されてから削除されるまでフィールド値が更新されてはいけない。更新されるとデータの不整合が生じるからだ。それが「サロゲートキー導入にともなう属性フィールドの更新不可制約」である。

 このような制約を、開発現場ではどのように扱っているのだろう。まず、まともにデータモデリングされていない現場では、{倉庫ID,商品ID}のユニーク制約さえ発想されない。それらの値を更新するようなアプリもふつうに生み出される。結果的に、使えば使うほどデータが濁ってゆくという困ったシステムが生み出される。

 まともにデータモデリングされている現場でも、たいていは「倉庫IDと商品IDの値を更新するようなアプリを設計しないように気を付けよう」程度のカジュアルな配慮しかされない。長期間の保守・改修を経てデータの不整合が起こらないとは言えない。

 せめてまともにデータモデリングされているという前提に立てば、フィールド定義レベルで「更新不可」を指定できるようであればスマートに対処できる。仮にそれらを更新してしまうようなアプリが設計されたとしても、更新不可フィールドとして定義されていれば水際で更新を抑止できるからだ。

 ところが残念なことに、そのような機構はRDBMSのレベルでは用意されていない。たとえば、DDLを次のように書きたいところだが、"NOT NULL"の仲間のような"NOT EDITABLE"なんてキーワードは存在しない。

CREATE TABLE ZAIKO(
IDZAIKO CHAR(7),
IDITEM CHAR(7) NOT EDITABLE,
IDSOUKO CHAR(7) NOT EDITABLE, ...
CONSTRAINT ZAIKO_PK PRIMARY KEY (IZAIKO),
CONSTRAINT ZAIKO_SK1 UNIQUE (IDITEM,IDSOUKO));

 けっきょく、属性フィールドの更新不可制約については「開発基盤」のレベルで対処せざるを得ない。すなわち、開発基盤上の「テーブル定義」の中でフィールド毎に「更新不可」を設定できるようになっていればいい。そのような機構を搭載している開発基盤をいくつか紹介しよう。

 まず、Salesforceでの更新不可設定のページは次のようなものだ。ユーザの権限タイプ毎に更新不可を設定できるようになっている。

150406a

 Salesforceは、OracleDB上でRDBを独自にエミュレートしている開発基盤で、その影響でPKには単独主キーしか認めていない。それだけに、更新不可設定の機構を盛り込むことでその「制約」を緩和している。つまり、開発基盤として単独主キー(サロゲートキー)しか認めないことが問題ではなく、更新不可設定の機構がセットになっていないことが問題なのである。Salesforceのあり方は理に適っている。

 次に、ジャスミンソフトの超高速開発ツールWagbyでの更新不可設定を見よう(次図)。リポジトリの設定ページで、機能のタイプに合わせて更新不可(読み込み専用)を指定できるようになっている。

150406b

 図からわかるように、更新不可だけでなく、さまざまな仕様要素をフィールドレベル(リポジトリ)で定義できるようになっている。従来はアプリ側に置かれた仕様要素が、テーブル側に移行されているということだ。開発・保守コストのほとんどは、アプリのコード(SQLやマークアップを含む)を扱うことに費やされる。それゆえに、テーブルの扱い方針に関する仕様をテーブルの拡張定義として持つことは理に適っている。開発されるアプリを「ありきたりでやせっぽち」な定義体に縮退させるためだ。

 拙作のOSS開発ツールXEAD Driverの例も挙げておこう。フィールド定義中の「更新不可」をチェックすれば、通常のパネル機能では更新できなくなる。

150406c

 これは「無条件の更新不可」のケースだが、「ある条件では更新不可だが、別の条件では更新を許す」といったケースもあるだろう。そのときには、テーブルスクリプトの中で、

if (...) {
 HT010_IDSIIRESAKI.editable = false;
} else {
 HT010_IDSIIRESAKI.editable = true;
}

のように書いておけばよい。もともとはこの形でしか更新不可設定が出来なかったのだが、最新版で「無条件の更新不可」を上掲のスタイルで指定できるようになった。結果的に、サロゲートキー方式で設計されたDBも手軽に扱えるようになった。

 最後に繰り返すが、サロゲートキー方式の場合、あるフィールドが更新不可として扱われるべきかどうかは、複合主キーを含んだオーソドックスなデータモデリングを経由しなければわからない。つまり、まともにデータモデリングされていなければ、どんなに気の利いた開発基盤を使おうが、生み出されるものは「使えば使うほどデータが濁ってゆくシステム」なのである。そのことを忘れてはいけない。

※図版に関して、salesforce.comの佐野氏とジャスミンソフトの贄氏にご協力いただいた。この場を借りてお礼を申し上げる。

*1.Ruby on Railsでも複合主キーは使えないわけではないが、アドオンで対応されているので、フレームワーク本体がアップデートされた途端に動かなくなったりする。

|

« ドメインの階層化とDSP | トップページ | モデル駆動開発勉強会(4/25@東京)で語ります »

コメント

コメントを書く



(ウェブ上には掲載しません)




トラックバック


この記事へのトラックバック一覧です: 「フィールドの更新不可制約」の必要性:

« ドメインの階層化とDSP | トップページ | モデル駆動開発勉強会(4/25@東京)で語ります »