時間の経過とともにときどき変化する値をモデリングする方法として、一般的には、変化のタイミングで値をデータベースに格納します。たとえば、時間とともに変化する商品価格を記録するには、各商品について、価格がいつ変わったか、およびその新しい価格を記録する Transaction オブジェクトを定義する方法が妥当です:
ProductLog
{
ProductId*
ProductLogDate*
ProductLogPrice
ProductLogName
}
それと同時に、クエリとして一般的なのは、商品および日付から、その日付時点での商品価格を確認することです。このシナリオをモデリングする方法として、従来は、商品および日付をパラメーターとして受け取り、対応する価格を返す Procedure オブジェクトを使用しました:
Procedure GetProductPriceInDate
Rules
parm(in:&ProductId, in:&Date, out:&ProductPrice);
Source
for each ProductLog order ProductId, (ProductLogPrice)
where ProductId = &ProductId
where ProductLogDate <= &Date
&ProductPrice = ProductLogPrice
exit
endfor
このソリューションは非常にシンプルですが、次のような欠点があります:
- 指定された商品および日付から価格を取得するクエリは適切に解決されますが、もう 1 つ別の一般的なクエリは解決されません: それは、指定の日付から、その日付時点の全商品の価格を取得することです。
- 指定の日付時点の商品価格がなかった場合にどうするかが問題です (たとえば、指定の日付が、商品が初めて記録された日付よりも前の場合)。
- このような場合、通常は、対応する価格がないことを示す特別な価格値 (通常は 0) を定義する必要があります。しかし、これは適切な方法ではありません。なぜなら、商品が無料 (価格 = 0) なのか、購入できないのかを判別できないからです。
- 価格以外にも項目属性 (指定の日付時点の名前など) を取得する必要がある場合、プロシージャーは複数の項目属性を返す必要があるため、式で使用できないという欠点があります。
- プロシージャーは、価格が必要になるたびに明示的に呼び出す必要があります。
ダイナミックトランザクションを定義すれば、これらの問題のないモデルを作成できます。
前の例と同じトランザクションを考えます:
ProductLog
Struct
{
ProductId*
ProductPriceDate*
ProductLogPrice
ProductLogName
}
ダイナミックトランザクションは次のとおりです:
Product //ダイナミックトランザクション
Struct
{
ProductId*
ProductQueryDate*
ProductPrice
ProductName
}
Data
Data Provider property = True
Used to property = Retrieve data
Data Provider
Parm(in:ProductQueryDate);
ProductPriceCollection
{
Product From ProductLog
where ProductLogDate = Max(ProductLogDate, ProductLogDate <= ProductQueryDate)
{
ProductId
ProductQueryDate
ProductPrice = ProductLogPrice
ProductName = ProductLogName
}
}
この場合、ダイナミックトランザクションに関連付けられているデータプロバイダーが、任意の可能な日付時点の商品価格を取得します。
また、ダイナミックトランザクションに関連付けられているデータプロバイダーにはパラメーター (ProductQueryDate) があり、クエリの実行時にこの項目属性に値が必要であることを指定しています。このため、次のクエリ (日付から、各商品の対応する価格を出力) は有効です:
For Each Product
where ProductQueryDate = &Today
Print ProductId, ProductPrice
Endfor
しかし、次のクエリ (すべての可能な日付のすべての商品価格の出力を「試行」) は無効です:
For Each Product
Print ProductId, ProductPrice
Endfor
これは、GeneXus では、すべての可能な日付を取得する方法がわからないからです (無限数であるという点を除く)。この場合、分析時に次のエラーが発生します:
error spc0214: グループ内のテーブル Product を行 8 からナビゲートするには項目属性 ProductQueryDate をインスタンス化してください。
ダイナミックトランザクションの使用方法は、ほかのトランザクションと同様です。項目属性を使用すれば、対応するナビゲーションが GeneXus によって解決されます。たとえば、販売日の商品の価格を確認する必要がある Sale トランザクションを考えます:
Sale // 簡素化のために販売ごとに 1 商品のみを想定
Struct
{
SaleId*
SaleDate
ProductId
ProductQueryDate
ProductPrice
ProductName
}
Rules
ProductQueryDate = SaleDate;
一時的な参照整合性が GeneXus によって自動的に制御されます。SaleDate に価格がない (つまり、ProductLog にレコードがない) 商品は Sale を記録できません。
この機能は GeneXus 16 Upgrade 9 以降で利用できます。
|