読者です 読者をやめる 読者になる 読者になる

Delegate

翻訳

http://www.hibernate.org/45.html

hibernateがなぜ複数のテーブルにマップされるサブクラスを許容しないのか聞かれることがあります(を使えば、"クラスの階層構造"を複数のテーブルにマップすることは、できます)。オブジェクトモデルをリレーショナルなモデルと同じかより小さいくらいの粒度で設計することは重要なことだと思います。もし、データモデルの設計者がいくつかのカラムを二つのテーブルで分割して保持する方針とするのであれば、発送の転換が必要となります。そういった分割をオブジェクトモデルで表現しない理由はありません。(オブジェクトモデルがより適切な粒度であるならば、再利用性も利ファクタリングのしやすさもよりよいものであるはずですから)。

ですが、オブジェクトの利用者に対してこのような粒度のすべてを見えるようにしたくないこともあります。リレーショナルモデルとして、CUSTOMERとCUSTOMER_HISTORYテーブルがあるものと考えます(また、二つのテーブルは主キーで関連づけられ、軽微な修正でも外部キーの関連に影響が出るものとします)。また、アプリケーションでは、Customerクラスだけをオブジェクトの利用者に見えるようにしたいとします。Customerクラスの実装は下記のとおり行うことができるでしょう。

public class Customer {
private Long id;
private CustomerHistory hist;
private String name;
....
public Long getId() {
return id;
}
private void setId(Long id) {
this.id=id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name=name;
}
private CustomerHistory getHistory() {
return hist;
}
private void setHistory(CustomerHistory hist) {
this.hist=hist;
}
....
public Calendar getFirstPurchaseDate() {
return hist.getFirstPurchaseDate();
}
public void setFirstPurchaseDate(Calendar cal) {
hist.setFirstPurchaseDate(cal);
}
....
}

public class CustomerHistory {
private Long id;
private Calendar firstPurchaseDate;
....
public Long getId() {
return id;
}
private void setId(Long id) {
this.id=id;
}
public Calendar getFirstPurchaseDate() {
return firstPurchaseDate;
}
public void setFirstPurchaseDate(Calendar cal) {
firstPurchaseDate = cal;
}
....
}

マッピングも、下記の通りにします。



CUSTOMER_SEQ




.....





.....

この実装は意外なものではないと思いますが、実はかなりいけてる箇所があります。delegateするCustomerHistoryクラスをプロキシとして宣言することにより、デプロイの時点でeagerなフェッチを行うかlazyなフェッチを行うか決定することができるようになっています。単に、の属性にouter-joinを付与しているだけで。

eagerとしたければ、下記のように。

lazyとしたければ、下記のように。

最小の追加コードで、オブジェクトモデルの粒度を細かくするとともに、効率的なデータアクセスを行うことができる、ということです。