30.8.3. 遅延ローディングプロセス
遅延ローディングは、一括読み込みと対になっています。あるフィールドを一括読み込みしない場合は、それを遅延ローディングにしなければなりません。bean の未ロードフィールドへのアクセスが行われると、JBoss は、そのフィールドとそれが属する
lazy-load-group のフィールドをすべてロードします。JBoss は set join を実行し、その後、すでにロードされているフィールドがあれば削除します。設定例を次に示します。
<jbosscmp-jdbc>
<enterprise-beans>
<entity>
<ejb-name>GangsterEJB</ejb-name>
<!-- ... -->
<load-groups>
<load-group>
<load-group-name>basic</load-group-name>
<field-name>name</field-name>
<field-name>nickName</field-name>
<field-name>badness</field-name>
</load-group>
<load-group>
<load-group-name>contact info</load-group-name>
<field-name>nickName</field-name>
<field-name>contactInfo</field-name>
<field-name>hangout</field-name>
</load-group>
</load-groups>
<!-- ... -->
<lazy-load-groups>
<load-group-name>basic</load-group-name>
<load-group-name>contact info</load-group-name>
</lazy-load-groups>
</entity>
</enterprise-beans>
</jbosscmp-jdbc>
この設定で bean プロバイダーが
getName() を呼び出すと、JBoss は、name、nickName、badnessを、それらがまだロードされていないとみなしてロードします。bean プロバイダーが getNickName()、name、nickName、badness、contactInfo、hangout がロードされます。遅延ローディングプロセスの詳細は次のとおりです。
- このエンティティのプレロードキャッシュ内のすべてのデータが、フィールドにロードされます。
- プレロードキャッシュによってフィールド値がロードされていた場合には、遅延ロードプロセスは終了します。
- JBoss は、このフィールドを含むすべての遅延ロードグループを見つけ出し、このグループに対して set join を実行し、すでにロードされていたフィールドがあれば削除します。
- クエリーを実行して必要なカラムを選択します。基本ロードプロセスと同様に、JBoss はエンティティのブロックをロードする場合があります。現行のエンティティのデータがコンテキストに格納され、他のエンティティのデータはプレロードキャッシュに格納されます。
30.8.3.1. リレーションシップ
CMR フィールドはフィールドでもありクエリーでもあるため、リレーションシップは、遅延ローディングでは特別なケースです。フィールドとしては、
on-load でブロックロードすることが可能で、現在求められているエンティティの値および次のいくつかのエンティティに対する CMR フィールドの値がロードされることを意味します。クエリーとしては、on-find を使用して、関連するエンティティのフィールド値をプレロードすることができます。
ここでも、最も簡単にローディングについて詳しく調べるため、使用シナリオを考察していきます。この例では、各 gangster とその hangout が入った HTML テーブルが生成されます。コード例は次のとおりです。
例30.3 リレーションシップの遅延ローディングのコード例
public String createGangsterHangoutHtmlTable()
throws FinderException
{
StringBuffer table = new StringBuffer();
table.append("<table>");
Collection gangsters = gangsterHome.findAll_onfind();
for (Iterator iter = gangsters.iterator(); iter.hasNext(); ) {
Gangster gangster = (Gangster)iter.next();
Location hangout = gangster.getHangout();
table.append("<tr>");
table.append("<td>").append(gangster.getName());
table.append("</td>");
table.append("<td>").append(gangster.getNickName());
table.append("</td>");
table.append("<td>").append(gangster.getBadness());
table.append("</td>");
table.append("<td>").append(hangout.getCity());
table.append("</td>");
table.append("<td>").append(hangout.getState());
table.append("</td>");
table.append("<td>").append(hangout.getZipCode());
table.append("</td>");
table.append("</tr>");
}
table.append("</table>");return table.toString();
}
この例では、gangster の
findAll_onfind クエリーの設定は on-find セクションから変わっていません。Locationエンティティおよび Gangster-Hangout リレーションシップの設定は次のとおりです。
例30.4 jbosscmp-jdbc.xml リレーションシップ の遅延ローディング設定
<jbosscmp-jdbc>
<enterprise-beans>
<entity>
<ejb-name>LocationEJB</ejb-name>
<load-groups>
<load-group>
<load-group-name>quick info</load-group-name>
<field-name>city</field-name>
<field-name>state</field-name>
<field-name>zipCode</field-name>
</load-group>
</load-groups>
<eager-load-group/>
</entity>
</enterprise-beans>
<relationships>
<ejb-relation>
<ejb-relation-name>Gangster-Hangout</ejb-relation-name>
<foreign-key-mapping/>
<ejb-relationship-role>
<ejb-relationship-role-name>
gangster-has-a-hangout
</ejb-relationship-role-name>
<key-fields/>
<read-ahead>
<strategy>on-find</strategy>
<page-size>4</page-size>
<eager-load-group>quick info</eager-load-group>
</read-ahead>
</ejb-relationship-role>
<ejb-relationship-role>
<ejb-relationship-role-name>
hangout-for-a-gangster
</ejb-relationship-role-name>
<key-fields>
<key-field>
<field-name>locationID</field-name>
<column-name>hangout</column-name>
</key-field>
</key-filaelds>
</ejb-relationship-role>
</ejb-relation>
</relationships>
</jbosscmp-jdbc>
JBoss は、finder に対して次のクエリーを実行します。
SELECT t0_g.id, t0_g.name, t0_g.nick_name, t0_g.badness
FROM gangster t0_g
ORDER BY t0_g.id ASC
hangout にアクセスすると、JBoss 次の 2 つのクエリーを実行して、hangout の
city、state、zipフィールドをロードします。
SELECT gangster.id, gangster.hangout,
location.city, location.st, location.zip
FROM gangster, location
WHERE (gangster.hangout=location.id) AND
((gangster.id=0) OR (gangster.id=1) OR
(gangster.id=2) OR (gangster.id=3))
SELECT gangster.id, gangster.hangout,
location.city, location.st, location.zip
FROM gangster, location
WHERE (gangster.hangout=location.id) AND
((gangster.id=4) OR (gangster.id=5) OR
(gangster.id=6) OR (gangster.id=7))
次の表でクエリを実行したものを示しています。
表30.4 on-find 最適化されたリレーションシップのクエリ実行
| id | name | nick_name | badness | hangout | id | city | st | zip |
|---|---|---|---|---|---|---|---|---|
| 0 | Yojimbo | Bodyguard | 7 | 0 | 0 | San Fran | CA | 94108 |
| 1 | Takeshi | Master | 10 | 1 | 1 | San Fran | CA | 94133 |
| 2 | Yuriko | Four finger | 4 | 2 | 2 | San Fran | CA | 94133 |
| 3 | Chow | Killer | 9 | 3 | 3 | San Fran | CA | 94133 |
| 4 | Shogi | Lightning | 8 | 4 | 4 | San Fran | CA | 94133 |
| 5 | Valentino | Pizza-Face | 4 | 5 | 5 | New York | NY | 10017 |
| 6 | Toni | Toothless | 2 | 6 | 6 | Chicago | IL | 60661 |
| 7 | Corleone | Godfather | 6 | 7 | 7 | Las Vegas | NV | 89109 |