Topics
Enterprise Architecture
Spring 2.0でのJPA(Java Persistence API)の利用
Pages:
1,
2,
3,
4,
5,
6
ドメインモデルでは、大半のエンティティは何か他のエンティティ(1つまたは複数)と関係があり、
Patientクラスもその例外ではありません。図2は、
Patientクラスとその関係を示したダイアグラムです。
図2: Patientクラスの関係
JPAでは、
OneToOne、
ManyToOne、
OneToMany、
ManyToManyの各注釈を用いて、関係とそれらの基数を指定します。どの関係フィールドにも、これらの注釈のうちの1つが付いている必要があります。たとえば、
Patientは
Addressとの間に
ManyToOne(多対1)関係があります。つまり、複数の患者が同じ住所になる場合があるということです。
Patientはまた、
Userクラス(患者のユーザ名とパスワードの情報が格納されている)との間に
OneToOne(1対1)関係があります。これはつまり、各
Patientオブジェクトはただ1つの
Userオブジェクトと関係するということです。
個々の患者は複数の処方箋を出されている場合があり、また、通院(医療記録の生成につながる)が複数回にわたる場合があるので、
Patientは、
Prescriptionとの間にも
Recordとの間にも
OneToMany(1対多)関係があります。逆に、各
Prescriptionや各
Recordは1つの
Patientとしか関係できないことになります。
JPAにおける関係の興味深い機能には、操作のカスケードがあります。「カスケード削除」機能は大半のリレーショナルデータベースでサポートされて いるので、それについては、すでによくご存知かもしれません。JPAでは、削除のような操作のカスケードという考え方が、挿入や更新といった他の操作にも 適用されています。
Patientクラスでは、挿入や更新の操作を自分と関係のある
Addressと
Userへ カスケードします(すなわち段階的に呼び出します)。データベースへの挿入はオブジェクトが永続化されるときに実行されるので、JPAでは挿入のことを 「永続化」と呼びます。また、更新を実行するとオブジェクトの変更部分が現在のJPA永続性コンテキストにマージされるので、更新のことを「マージ」と呼 びます。この呼び方が紛らわしいような気がしても、ご心配なく。すでに永続化されているオブジェクトを更新する場合にはmergeを呼び出し、新しい永続 オブジェクトをデータベースに挿入する場合にはpersistを呼び出すということだけ覚えておいてください。
persist(永続化)、merge(マージ)、remove(削除)といった特定の操作をカスケードするかどうかの決定は、なかなか難しいことがあります。
Patientクラスの場合は、persist操作は
Addressと
Userにカスケードされます。アプリケーションでは、新しい
Patientが挿入されるたびに、新しい
Addressと
Userも挿入する必要があるからです。同様に、
Patientが更新されるときは、
Addressと
Userも場合によっては更新される必要があります。
Prescriptionと
Recordの場合は、動作が異なります。アプリケーションには
Prescriptionや
Recordを明示的に永続化(および更新)する操作が用意されているため、これらの操作を
Patientからこれらのクラスにカスケードする必要はありません。
さて、この記事の前のセクションで、複数の
Patientが同じ
Addressを参照することが可能であると述べました。
Patientから
Addressへの関係が
ManyToOne(多対1)だからです。しかし、つい先ほど、
Patientはinsert操作を
Addressにカスケードし、その結果、データベース内の患者ごとに新しい住所が生成されることになるとも述べました。これは、一体どういうことなんでしょうか。ここで取り上げているのは、自動生成される主キーと
Patient-
Address間のカスケード挿入を使用する場合の興味深い効果なのです。住所の主キーはデータベースによって自動的に生成されるので、どの
Addressオブジェクトも一意な主キーを持つことになり、同じ実住所を参照する2つの異なる
Addressオブジェクトをデータベースに挿入することが可能です。MedRecも含めて多くのアプリケーションの場合には、これで結構ですが、このような重複する住所を防止する必要がある場合は、DAOで何か追加のロジックを実行する必要があります。
MedRecのエンティティクラスがJPAではデータベーススキーマに、WebLogic Server 9.1のWebサービス実装ではXMLに、それぞれマッピングされるということで、エンティティクラスの設計に影響を及ぼす更なる問題がいくつか持ち上がりました。
JPAでは一方向の関係も双方向の関係もサポートしていますが、MedRecのエンティティクラスを見てみると、関係がすべて一方向であることがわかります。Webサービスバインディングで双方向の関係をサポートできなかったために、こうする必要があったのです。
もう1つ問題が持ち上がったのですが、これは、多値関係フィールドには
java.util.SetのようなJavaコレクション型を使用するというJPAの要件があったためです。WebLogic Server 9.1のWebサービス実装では
Collection型をサポートしていないことがわかっています。それでは、この問題をどのように回避したのでしょうか。
オブジェクト/リレーショナルマッピングがエンティティのフィールドに対してもメソッドに対しても定義できることを思い出してください。JPA側の こうした柔軟性は、結果的に非常に重要でした。一方、Webサービスでは、クラスのpublicなプロパティアクセサメソッド(
getXXX()メ ソッド)を使用して、XMLにマーシャリングされるプロパティを定義します。フィールドを使って永続性マッピングを定義し、XMLバインディングのほうは クラスのメソッドで定義されるようにすることで、これら2つのマッピングを別々にしておくことができました。多値関係は、永続性を実現するために内部的に
Setオブジェクトを使用しましたが、XMLバインディングで処理できる配列としてプロパティアクセスメソッドを通じて公開されました。
このことを具体的に説明するために、この変換を実行したプロパティアクセスメソッドの例を
Recordクラスから抜粋して以下に示します。
public Prescription[] getPrescriptions() {
if (prescriptions == null)
return null;
return (Prescription[]) prescriptions.toArray(new
Prescription[prescriptions.size()]);
}
内部的には、このメソッドは
java.util.Set型の永続フィールドprescriptionsにアクセスします。
Setは、Webサービス実装で処理できる配列に変換されます。Webサービス統合に携わった経験から、私たちは、JPA、およびJPAが既存のアプリケーションやインフラストラクチャと統合できることに深く感銘を受けました。
これで、永続クラスについての考察は終了です。多くのルールや制限事項に従う必要があるように思えるかもしれませんが、実際には、JPAルールの大 半は良いコーディング習慣を具体化したものにすぎず、おそらくは、あれこれ考えなくても、気がついたらそれらに従っていたということになるでしょう。
|
|