今回は、説明しにくいなぁ。でも図とか面倒なので、文字のみで失礼しますヨ。
欲しい機能
「議事録管理システム」としましょうや。
会議やミーティングの出来事を記録しようと言うモノとしましょうね。この「会議トランザクション」の情報には、シンプルに「議事内容」と「参加者」くらいの項目で考えてくださいな。で、「議事内容」はその都度のデータとして、「参加者」のデータは、どうでも良い一見(イチゲン)さんも参加しますが、ウチの社員(「社員マスタ」{シンプルに「社員ID」と「名前」くらいの項目で考えてくださいね}で管理されている)が参加している。ので、これをリンクさせる・・・って、っま、フツーの設計ですよね。
実装では、「会議トランザクション」に「参加者ID」と「参加者名」の項目を作って、社員マスタからの引用であれば「参加者ID」には「社員ID」がセットされ、ドーデモ良いイチゲンさんの場合は「参加者ID」に「0」とか「99999」とか・・・をセットする。(管理対象外:いわゆる雑コード扱いですね)
こうしておけば、社員さんが事情で名前が変わっても、「その会議のときの名前(トランザクションデータ)」と「現在の名前(マスタデータ)」が、ちゃんと表現できるし、「社員ID」で「会議トランザクション」を抽出すれば、彼・彼女の参加した会議の一覧がgetできて、しっかりと管理対象じゃないですか。
ここまで、イイよね。
で、運用を考えると、当然のことながら、社員登録したけどヘボこいて、削除する・・・って、良く、あるよね(^-^);。だけど一度でもトランザクションデータに引用されている場合は、削除されちゃ困る。・・・そうそう、事情で名前や性別が変わっても良いけど、削除されちゃうと整合性が取れないモノね。
そんなときには、ソースコードにゴリゴリ記述していたら、何か処理を増やすたびに「ヒヤヒヤ」ものですよね。だから、こんなコトはご存知のようにRDBS側で「外部キー」の設定をしておいて、依存関係にキズを付けるような「行為(削除)」があったら、エラー(例外)を出してやる・・・ってすれば、良いワケだ。
で、問題
でも、一方のイチゲンさんの「参加者ID」は、「社員マスタ」には居ないので、トランザクションに登録できないジャン!!!!!
対処
こりゃ困った。でもヨク・ヨク・ヨークpostgresql のdocument(create table あたり)を調べると、nullだけは特例で外部キーの制約対象から外れるみたいです。(パラメータにもよるケドね)
実際に試してみたら、思い通りの結果で「ヤッタぜ、ベイビー」。int8の項目にnullを入れて問題解決!
で、次の問題
ちょっと心配は、O/Rマッピングが上手く行くのか?なんせlong(プリミティブ型)で待っているクラスに、nullをぶつけるのだから・・・ねぇ。ほら、やっぱりエラーじゃんか!
解決案を探す
外部キー制約で、特定の値を除く・・・とかあれば、そこに「0」やら「9999」を設定して・・・、結構調べたが、そんなモノはないようでした。では、Hibernate側で、ゼロだったらnullに変換とか・・・そんな都合の良いのはないようでした。
・・・で、諦めかけて、カッコ悪いけど、ダミーのマスタデータ「社員ID:ゼロ」を入れるしかないのか!ああああ・・・・そんな「逃げ作業」は嫌いじゃ・・・。・・・と、苦しんでいたトコロ、天使のように微笑みかけてくれるサイトを発見しました。
結論
そうなんです。先入観はイカンです。プリミティブ型の項目に「null」はイカンでしょ。だからラッパークラス(java.lang.Long)を使えば、「null」なんて当然あり得るじゃんか!本当に目からウロコでした。特定の数値や文字列でマスタへの依存を表現しようと言う発想も、考えてみれば「姑息」な、昔風な「逃げテクニック」なのカモですね。だって「null」はズバリ・「空っぽ」「無いよ」、じゃないですか!・・・・いたく納得でした。