モデル間の計算(トランザクション)
最終更新日: 2021年12月15日
R8 | R9
出庫モデル syukko の登録処理時に、同時に(関連する)在庫モデル zaiko の値を変更する例を説明します。
「商品」と「商品在庫」は 1:1 の関係があります。このため、「商品在庫」の主キーは、「商品」を参照するようにしています。
ここではトランザクション系である「出庫伝票」に注目します。このモデルの新規登録処理で、商品在庫を同時に変動させる必要があります。また、商品在庫を超える出庫要求については、エラーを返すようにします。
商品在庫マスタモデルに、図2に示す初期データを設定しました。それぞれ在庫数を100としています。
出庫伝票を作成します。指定商品を一つ、出庫します。(図3)
出庫伝票が作成されました。このタイミングでトランザクション処理が正常に終了しています。
商品在庫マスタを確認します。在庫が減じられていることがわかります。
在庫数を超える数を出庫しようとするとエラーメッセージを返すようにしました。(図6)
図1に示した4つのモデルを定義します。
倉庫IDと倉庫名、倉庫の管理者を定義しました。
商品ID、商品名、単価を保持します。また、一つの倉庫に紐付けられます。
主キーである「商品」は、商品マスタと 1:1 の関連を持ちます。
主キー「商品」項目は、順序を使わない設定としてください。
どの商品をいくつ出庫したかを記録します。
ここで商品の出庫数に合わせて、商品在庫マスタの在庫数量を減らすために、モデル参照項目「商品」にトランザクションの設定を行います。(図12)
モデル名を明記しているのは、今回のケースにおいては(参照先のモデルが)「商品」ではなく「商品在庫」となっているためです。「商品」と「商品在庫」は 1:1 の関係にあり、「商品在庫」の主キーは、「商品」の主キーと同じという関係としています。
新しくトランザクションを設定したとき(新規登録・更新・削除・コピー登録のチェックを行ったとき)は、ビルド処理を行ってください。
実際のトランザクション処理コード(トランザクションスクリプト)は、図12における「トランザクション制御時のスクリプト」欄に記述します。このコードはトランザクション境界の中で実行されます。[トランザクション境界について...]
新規登録とコピー登録の区別はありません。SCREENTYPE 定数を用いて判別することができます。これは画面種別を返すSCREENTYPE関数の値を保持しています。
新規登録時とコピー登録時は同じスクリプトファイルが呼ばれますが、コピー登録時は処理しないような制御を行う例を示します。
繰り返しコンテナ内の項目にトランザクションを指定することができます。
同時に複数のデータが書き換えられていることがわかります。(図15)
図11の出庫伝票の定義を変更し、明細を用意しました。(図16)
ファイル名やファイルの保存位置は変わりません。
Wagbyの外部キー関係では、一つの親データが複数の子データを管理できます。
次の例では親モデル名 parent と、子モデル名 child を用いて説明します。
子モデル child は、親モデルを指し示す外部キー項目 pkey を持つとします。このとき、この pkey 項目に対してトランザクションスクリプトを記載できます。
上図の例は、子モデル新規登録のタイミングで、子モデルの値を親モデルの項目へ転記するものです。
Wagby の標準では、モデルの更新制御は悲観ロックを用います。これを楽観ロック方式に切り替えることもできます。トランザクション実行時のロックは、指定した方式に準拠して制御されます。
悲観ロックでは、対象となるデータが更新中(更新画面が開いた状態)の場合、登録・更新処理を行おうとすると画面には "失敗した" というエラーメッセージが表示されます。
楽観ロックでは、対象となるデータが別に更新されていた場合、同様にエラーとなります。
いずれの場合も、そのトランザクションは失敗します。これは正しい動作です。
ここまでの説明は Wagby が標準で提供するモデル参照という仕組みを用いて自身に紐づくモデルが定まっている場合に適用できるものです。そのためトランザクション処理を記述する箇所は限定されています。
トランザクションを設定した場合、生成されるファイル名は次の通りです。
モデルIDEntityService_doTransactionBy${トランザクションを設定した項目ID}InsertTransaction.js在庫管理のイメージ
例
エラー時の扱い
この場合はデータベースの値は書き変わりません。
定義方法
倉庫マスタ
商品マスタ
商品在庫マスタ
出庫伝票
ここでは、新規登録時に「在庫」モデルと連動する指定を行います。
ワンポイント
参照先モデルがそのままトランザクション処理の対象モデルに等しい場合は、モデル名を空白とすることもできます。本欄が空白の場合は、参照モデル名が利用されます。
一度設定したあとは、ビルド処理は不要です。トランザクションスクリプトの変更は即座に反映されます。
文法
var suryou = zaiko.suryou;
var syukko_num = syukko.syukkoNum;
if (suryou - syukko_num < 0) {
return "在庫 "+suryou+" に対して "+syukko_num+" を出庫しようとしました。";
}
zaiko.suryou = suryou - syukko_num;
return null;
新規登録とコピー登録
if (SCREENTYPE == "copy") {
/* コピー登録時は処理を行わない */
return null;
}
/* 登録時にのみ実行される */
...
}
繰り返しコンテナとの連携
例
図14は、出庫伝票の明細で、複数の商品を同時に指定する例です。
定義方法
トランザクションスクリプトの変更
スクリプト内では、繰り返しコンテナ "details" を利用できます。このとき、複数の繰り返しコンテナのデータ毎に、このスクリプトが実行されます。(図16では3つの明細データがあったため、各データ単位でこのスクリプトが合計3回、実行されます。)
/* トランザクションで使うオブジェクト sykko, zaiko は利用可能になっている。
これは定義ファイル「トランザクション指定」に含めたモデルである。
繰り返しコンテナも利用できる。details という名前のオブジェクトが用意されている。*/
var suryou = zaiko.suryou;
/* detailsは明細データ毎に呼び出された値がセットされる */
var syukko_num = details.syukkoNum;
if (suryou - syukko_num < 0) {
return "在庫 "+suryou+" に対して "+syukko_num+" を出庫しようとしました。";
}
zaiko.suryou = suryou - syukko_num;
return null;
外部キー子モデルとの連携
parent.pname = child.cname;
対象データがロックされている場合の動作
Service/DaoクラスやSQLを利用する
トランザクション境界
仕様・制約
生成されるスクリプトファイル
モデルIDEntityService_doTransactionBy${トランザクションを設定した項目ID}UpdateTransaction.js
モデルIDEntityService_doTransactionBy${トランザクションを設定した項目ID}DeleteTransaction.js