既定では、ダイナミックトランザクションを定義すると、[ Update Policy ] プロパティが [ Read Only ] に設定されます。データは実行時に照会され、トランザクションフォームによる更新、挿入、削除はできません。
しかし、データを更新できるほうが実用的な場合もあります。
データの更新が可能なダイナミックトランザクションを定義するには、トランザクションプロパティを次のように設定する必要があります:
また、[ Data Provider ] プロパティを [ True ] に設定したことにより自動的に作成されるデータプロバイダーを完成させる必要もあります。
それでは、データの更新を可能にしたダイナミックトランザクションの使用を提案するシナリオを見てみましょう。
次のトランザクションは、体重の変化を追跡する GeneXus ナレッジベースです:
Person
{
PersonId*
PersonName
GenderId
GenderName
}
Gender
{
GenderId*
GenderName
GenderMembers = count(PersonName)
}
WeightLog
{
PersonId*
WeightLogDate*
WeightLogKilos
}
システムは既に稼動しており、ユーザーが体重だけでなく、ほかの部分の測定値、たとえば、胸囲や胴囲の追跡も希望しているとします。新しいデータを格納するには、データベースモデルを再設計する必要があります。新たに追跡する測定値ごとに新しい Transaction オブジェクトを作ることもできますが、どのような種類の測定値にも 1 つの Transaction で間に合わせる設計のほうが優れた (そして拡張性の高い) ものになります:
MeasureLog
{
PersonId*
MeasureId*
MeasureLogDate*
MeasureLogValue
}
測定トランザクションと連結します:
Measure
{
MeasureId*
MeasureName
}
ここで、[ Data Provider ] プロパティが [ True ] 、[ Used To ] プロパティが [ Retrieve Data ] 、[ Update Policy ] プロパティが [ Read Only ] のとき、関連するデータプロバイダーは次のようになります:
これ以降、すべての測定値は、新しい MeasureLog トランザクションに関連付けられた物理テーブルに格納されるため、WeightLog トランザクションは必要なくなります。ただし、For Each ステートメントなど、アプリケーションのコードのさまざまな場所で、引き続きベーストランザクションとして参照されます。そのため、WeightLog トランザクションを削除し、これを参照している部分をすべて修正する代わりに、ダイナミックトランザクションに変更することをお勧めします。
そのためには、次のようにする必要があります:
- WeightLog の [ Data Provider ] プロパティを [ True ] にします。
- WeightLog の [ Used to ] プロパティを [ Retrieve Data ] に設定します。
- 自動作成され、「WeightLog_DataProvider」と名付けられたデータプロバイダーを、次の図のように完成させます:
これらの定義により、WeightLog トランザクションは、これまでとまったく同じようにクエリで使用することができます (これを参照している For Each ステートメントのコードを変更する必要はなく、項目属性もそのままグリッドや printblock などで使用できます)。ただし、トランザクションをダイナミックとして定義した場合、関連づけられている物理テーブルは存在しなくなることを覚えておいてください。したがって、処理を進める前に、データを移動する必要があります (ここでは体重の測定値を WeightLog から MeassureLog テーブルへ移動します)。
更新についてはどうでしょうか。ユーザーは WeightLog トランザクションフォームの実行に慣れているため、MeasureLog トランザクションと WeightLog トランザクションの両方を使用できるのが理想的です。
WeightLog トランザクションの [ Update Policy ] プロパティを [ Updatable ] に設定すると、そのフォームでユーザーがデータを編集できるようになります。しかし、更新したデータはどの物理テーブルに格納されるのでしょうか。
この場合、WeightLog トランザクションの Events セクションに Insert、Update、Delete イベントのコードを記述して、意図を明確にする必要があります。この例の解決策としては、次のように、ビジネス コンポーネント コンセプトを使用して、データを MeasureLog 物理テーブルに格納するのが理に適っています。
Event Insert(&Messages)
&MeasureLog = new()
&MeasureLog.PersonId = PersonId
&MeasureLog.MeasureId = 1
&MeasureLog.MeasureLogDate = WeightLogDate
&MeasureLog.MeasureLogValue = WeightLogKilos
&MeasureLog.Insert()
&Messages = &MeasureLog.GetMessages()
Endevent
Event Update(&Messages)
&MeasureLog.Load(PersonId, 1, WeightLogDate)
&MeasureLog.MeasureLogValue = WeightLogKilos
&MeasureLog.Update()
&Messages = &MeasureLog.GetMessages()
Endevent
Event Delete(&Messages)
&MeasureLog.Load(PersonId, 1, WeightLogDate)
&MeasureLog.Delete()
&Messages = &MeasureLog.GetMessages()
Endevent
ここで、Insert()、Update()、および Delete() メソッドを &MeasureLog ビジネスコンポーネント変数に適用した後、(&Messages コレクション変数で) メッセージやエラーをトリガーしています。このように、イベントごとに &Messages 変数をパラメーターとして宣言することにより、これらのメッセージは WeightLog ダイナミックトランザクション自身のメッセージであるかのように透過的に表示されるようになります。
こうすることで、WeightLog ダイナミックトランザクションは、以前とまったく同じように使用できます。また、依存プログラムを変更する必要は必要ありません。これは、トランザクションをビジネスコンポーネントとして使用する場合にもあてはまります。その理由は、更新を可能にするのがダイナミックトランザクションで、対応するデータ格納イベントはコードとして記述されるためです。
検討事項
この機能を使用する場合は、次の点に注意してください:
- この機能は、複数レベルのダイナミックトランザクションでは使用できません。
- MySQL を使用している場合、バージョン 5.7.7 以降が必要です。
クラウドで Java アプリケーションをプロトタイプするには、apps6.genexus.com を使用します。
- Informix および SQLite ではこの機能がサポートされていません。
|