2013年3月10日日曜日

ローカル式の挙動に関するあれこれ

GeneXusのコードの中には、記述してあるコードの順序と実際に動作する時の順序(生成されるソースコードの順序)が違っているケースがあります。具体的にはFor eachを使わないローカル式がそれにあたります。


ケース1.ローカル式の条件に変数を使用している場合

あるコードブロック内にて変数の初期化後にローカル式がある場合、ローカル式が先に評価されるため、条件内の変数が未設定の状態で実行されます。

&CustomerId = 1
&Count = Count( InvoiceDate, CustomerId = &CustomerId )
//Countが先に評価されコンディション内の&CustomerIdの値は初期状態

ケース2.Newコマンド内にローカル式を記述した場合

Newコマンド(つまりInsert)が先に評価され、ローカル式の実行はInsertの後になります。結果として、ローカル式の結果をセットしている項目属性は未設定の状態で保存されます。
又、Newコマンドの外側でfor each以外のループ処理をしている場合(例えば、カウンタやコレクションによるforコマンド)、1回目のループでは未設定、2回目のループでは1回目の式で取得した値がセットされるという、ループ処理がずれた結果になります。

New
   Attribute1 = &val1
   Attribute2 = Max( Attribute2, Attribute1 = &val1) + 1
   Attribute3 = &val3
Endnew

ケース3.BC(ビジネスコンポーネント)を使ったInsertにローカル式を記述した場合

これは例外ケースです。BCの操作はDBアクセスと認識されないため(DBに対するI/OはBC内に隠蔽かされている為)、ローカル式が先に評価され、取得した値を元にBCを使ったインサートが実行されます。この場合は見た目と同じ挙動になります。

&BC.Attribute1 = &val1
&BC.Attribute2 = Max( Attribute2, Attribute1 = &val1)
&BC.Attribute3 = &val3
&BC.Save()


ケース1と2の対処としては、ローカル式を使用する部分をサブルーチンに分割する事により、明示的に処理の順序を指定することが可能です。

ケース1
&CustomerId = 1
Do ‘GetCountInvoice’ //サブルーチン呼び出し

//ローカル式をサブルーチン化
Sub ‘GetCountInvoice’
   &Count = Count( InvoiceDate, CustomerId = &CustomerId )
EndSub

ケース2
New
   InvoiceId = &InvoiceId
   Do ‘GetMaxDetailId’ //サブルーチン呼び出し
   InvoiceDetailId = &max + 1
   ProductId = &ProductId

//ローカル式をサブルーチン化
Sub ‘GetMaxDetailId’
   &max = Max( InvoiceDetailId, InvoiceId = &InvoiceId )
EndSub


0 件のコメント:

コメントを投稿