繰り返しコンテナ - 独立したモデルとして扱う

最終更新日: 2020年3月14日
R8 | R9

「見積書」モデルに含まれる繰り返しコンテナ「内訳」を、別モデル「見積明細」として操作できるようにします。 図1にイメージを示します。

繰り返しコンテナはデータベース上は別テーブルとなっており、テーブル名は次のルールで決められています。

Model ID + "$" + Container ID
図1 繰り返しコンテナを別モデルとして扱うイメージ

見積書モデルの繰り返しコンテナは図2のとおりです。

図2 見積書モデル詳細画面

追加した「見積明細」モデルの検索画面を図3に示します。繰り返しコンテナ部分がデータとして検索できます。

図3 見積明細モデル検索画面

「見積明細」モデルの一覧画面を図4に示します。内容は図1と同じです。

図4 見積明細モデル一覧画面

定義方法

繰り返しコンテナを定義した「見積書」モデルを図5に示します。

図5 見積書モデルの定義

図5における赤枠の繰り返しコンテナ部分を抜き出して、「見積明細」モデルとして定義したのが図6です。

定義のポイントは次のとおりです。

  • 主キーは「見積書」モデルと同一とします。この例では "id" です。
  • 「繰り返しコンテナ名 + "jshid"」となる項目が必要です。型は整数型です。この例では "precordjshid" です。
  • "id" と "precordjshid" の二つで複合主キーとします。(それぞれに「主キーとして利用する」を有効とします。)
  • モデル内の項目は、参照元の繰り返しコンテナと同じ項目ID、同じ型としてください。項目名の部分は変更できます。
  • 参照元の繰り返しコンテナの項目を減らすことはできますが、追加することはできません。
図6 見積明細モデルの定義

図7に、繰り返しコンテナID "precordjshid" を主キーとして利用する設定を行ったところを示します。順序は利用しません。

図7 主キーの設定

見積明細モデルの「画面>その他>データベースの詳細」を開きます。「テーブルを作成する」を無効とし、「物理テーブル名」を "quotation$precord" と直接、明記します。さらに「キャッシュを有効にする」を解除します。

図8 テーブルを作成するを解除し、物理テーブル名を指定する、キャッシュを無効化する

更新を行わないように設定する

別モデルとして用意した「見積明細」モデルは、登録・更新・削除は行なわないようにしてください。参照のみで運用することを想定しています。(データ入力は、元々の「見積書」モデルでのみ行います。)

図9 新規登録画面を作成しない
図10 更新画面を作成しない

更新を行いたい場合

上の説明では「更新画面を作成しない」としていますが、その理由は次のとおりです。

  1. 元のモデルと、繰り返しコンテナ独立モデルの双方で更新すると、メモリに保持されているキャッシュの整合性がとれない。
  2. 両方が同時に更新処理を行ったとき、ロックキーが異なるため、ロック機構が働かない。

この問題を回避する方法を紹介します。

キャッシュを使わない

元のモデル(上の例では「見積書」)と、繰り返しコンテナ独立モデル(上の例では「見積明細」)のそれぞれで、キャッシュを無効にします。パフォーマンスは不利になります。

同時に更新されない運用とする

例えば見積書に制御フラグを用意します。このフラグ値によって、一方の更新ボタンを無効にするというボタン表示制御式を用意し、同時更新を回避します。

ロックキーを同じにする

繰り返しコンテナ独立モデル(上の例では「見積明細」)のロックキーを、元のモデル(上の例では「見積書」)に合わせます。この場合、繰り返しコンテナ独立モデルの個々のレコード単位でのロック制御は行えなくなります。(繰り返しコンテナ行全体で、一つのロックキーとなるためです。)

スクリプトで利用する

スクリプトで繰り返しコンテナ独立モデルを操作することができます。

ここでは customer モデルに favorite (趣味) という繰り返しコンテナを用意したとします。また、繰り返しコンテナ独立モデル Favorite を定義したとします。

var Favorite = Java.type("jp.jasminesoft.wagby.model.favorite.Favorite");
var entityService = p.appctx.getBean("FavoriteEntityService");
var key = new Favorite.Key();/*複合キーの扱いになる*/
key.id = 1000;
key.contjshid = 1;
var favorite = entityService.findById(key);
print(favorite);

トラブルシューティング

データインポート時や init_db 実行時に警告が発生する

system.log や initdb.log に次のような警告が出力されることがあります。

Invocation of init method failed; nested exception is org.hibernate.MappingException: Foreign key (...) must have same number of columns as the referenced primary key (...)

このExceptionが発生した場合は、主キーの定義が誤っている可能性があります。主キーの定義の見直しを行って下さい。