マスタ/詳細関係(M/D)
データセットの操作(FireDAC) への移動
FireDAC では、データセット間のマスタ/詳細関係を柔軟にサポートしています。
概要
マスタ/詳細関係を使用すると、現在のマスタ データセット レコードに基づいて詳細データセットを自動的にフィルタリングできます。たとえば、マスタ データセットに "Order" レコードがあり、詳細データセットに "Order Line" レコードがあるとしましょう。 この場合、詳細データセットには現在の注文の明細行のみ表示されます。
マスタ データセットには特別なセットアップは必要ありません。
FireDAC には、マスタ/詳細関係の詳細データセットをセットアップする基本手法が以下のように 2 つ用意されています:
- パラメータベース: マスタ データセット フィールド値が詳細 TFDQuery または TFDStoredProc パラメータに割り当てられたあと、詳細データセット クエリが再実行されます。
- 範囲ベース: マスタ データセット フィールド値は、詳細データセットに範囲を適用するのに使用されます。詳細データセットは、現在のアクティブなインデックスを持つ任意の FireDAC データセットの可能性があります。
これらの手法は組み合わせることができます。両者のどちらかを選択する場合は、以下の表を考慮に入れます:
機能 | パラメータベース | 範囲ベース |
---|---|---|
詳細クエリの結果、限られた数のレコードが返される。 | + | |
詳細レコードは最新である。 | + | |
マスタの変更ごとに発生するトラフィックと DBMS の処理負荷が軽減される。 | + | |
キャッシュされた更新がマスタ変更時に保存される。 | + | |
オフライン モードで動作する。 | + | |
一元的キャッシュ更新とその伝播をサポートしている。 | + |
さらに、FireDAC には、マスタ/詳細関係のデータセットに対して キャッシュされた更新 モードが以下のように 2 つ用意されています。
- "分散的にキャッシュされた更新" モード: 各データセットでは、他のデータセットとは無関係に変更を追跡します。
- "一元キャッシュ更新" モード: マスタ/詳細関係の少数のデータセットで単一の変更ログを共有します。マスタ データセットでは、自動インクリメント フィールド値も含め、変更を連鎖的に詳細データセットに伝播できます。
パラメータベースの M/D
パラメータベースの M/D 関係をセットアップするには、以下の手順を実行します:
- フォームに TFDQuery(またはその他の任意の FireDAC データセット)をドロップします。
- このデータセットの名前を qOrders にします。これは、マスタ データセットです。
- これをセットアップします - 以下のような SQL を割り当てます:
SELECT * FROM {id Orders}
- 4. TDataSource をフォームにドロップします。dsOrders と名前を付けます。DataSet プロパティを qOrders に設定します。
- 5. TFDQuery をフォームにドロップします。qOrderDetails と名前を付けます。 これが詳細データセットです。
- 6. これをセットアップします - 以下のような SQL を割り当てます:
SELECT * FROM {id Order Details} WHERE OrderID = :OrderID
- 7. その後、MasterSource を dsOrders に設定します。基本セットアップはこれで終了です。
これはどのように動作するのでしょうか?FireDAC が qOrderDetails に、qOrders フィールドと qOrderDetails パラメータのペアのリストを作成します。各ペアの要素は:
- MasterFields が指定されていない場合、同じにパラメータになります。
- そうでない場合は、同じ位置、MasterFields リスト内の同じフィールド、Params コレクション内の同じパラメータになります。
現在の qOrders レコードが変更されると、FireDAC は各パラメータに、対応するフィールド値を割り当てます。今回の例では、qOrderDetails :OrderID パラメータが qOrder OrderID フィールド値を取ります。 その後、qOrders が再実行されます。
メモ: BeforeOpen および AfterOpen イベントは、詳細データセットには発生しません。代わりに、OnMasterSetValue を使用します。
範囲ベースの M/D
範囲ベースの M/D 関係をセットアップするには、以下の手順を実行します:
- フォームに TFDQuery(またはその他の任意の FireDAC データセット)をドロップします。
- qOrders と名前を付けます。 これは、マスタ データセットです。
- これをセットアップします - 以下のような SQL を割り当てます:
SELECT * FROM {id Orders}
- 4. TDataSource をフォームにドロップします。 dsOrders と名前を付けます。 DataSet を qOrders に設定します。
- 5. TFDQuery をフォームにドロップします。qOrderDetails と名前を付けます。 これが詳細データセットです。
- 6. これをセットアップします - 以下のような SQL を割り当てます:
SELECT * FROM {id Order Details}
- 7. MasterFields を ORDERID に設定し、IndexFieldNames を ORDERID に設定し、MasterSource を dsOrders に設定します。基本セットアップはこれで終了です。
これはどのように動作するのでしょうか? FireDAC が qOrderDetails に qOrders フィールドと qOrderDetails フィールドのペアのリストを作成します。各ペアのフィールドは同じ位置、MasterFields 内の同じマスタ フィールド、IndexFieldNames 内の同じ詳細フィールドになります。
現在の qOrders レコードが変更されると、FireDAC がその範囲を qOrderDetails に適用します。ここで、詳細フィールドが対応するマスタ フィールドと同じになります。今回の例では、qOrderDetails OrderID フィールドが qOrder OrderID フィールドと同じです。
手法の組み合わせ
両方の手法を組み合わせるには、アプリケーションでパラメータベースのセットアップと範囲ベースのセットアップの両方を使用し、fiDetails を FetchOptions.Cache に含めなければなりません。その場合、FireDAC は最初、範囲ベースの M/D を使用します。データセットが空であれば、FireDAC はパラメータベースの M/D を使用します。新たにクエリされたレコードは内部レコード記憶域に追加されます。
さらに、TFDDataSet.OnMasterSetValues イベント ハンドラを使用して、M/D の動作をオーバーライドすることもできます。
詳細データセットの編集
新しいレコードが詳細データセットに挿入されると、M/D 関係に関与しているフィールドに、対応するマスタ データセット フィールド値が自動的に設定されます。詳細データセット フィールド リストは以下のように定義されます:
- パラメータベース M/D の場合 - DetailFields(指定時)。未指定時は、同じ名前をパラメータとするフィールド。
- 範囲ベース M/D の場合 - インデックス フィールド。
詳細レコードを挿入するには、マスタ データセットが閲覧状態(State dsBrowse)でなければなりません。マスタ データセットと詳細データセットの両方を挿入状態(dsInsert)または編集状態(dsEdit)にすることはできません。
マスタ データセットと詳細データセットが "キャッシュされた更新" モードにある場合は、アプリケーションで TFDSchemaAdapterd を使用して、一元キャッシュ更新とその伝播を有効にすることができます。さらに言えば、マスタ データセットと詳細データセットの SchemaAdapter プロパティが同じ TFDSchemaAdapter を指している必要があり、詳細データセットの FetchOptions.DetailCascade は True にします。
M/D 内のナビゲーション
アプリケーションでマスタ データセット内をナビゲートする必要がある場合、詳細データセットはマスタ レコードが変更されるたびに更新されます。この処理はリソースを消費し、ナビゲーションが遅くなるおそれがあります。M/D の同期を一時的に無効にするには、アプリケーションでマスタ データセットに対して、以下のように DisableControls / EnableControls を呼び出します:
qOrders.DisableControls;
try
qOrders.First;
while not qOrders.Eof do begin
.....
qOrders.Next;
end;
finally
qOrders.EnableControls;
end;
M/D の同期を強制的に無効にする場合は、マスタ データセットに対して ApplyMaster メソッドを呼び出します。特定の詳細データセットに対して M/D の同期を一時的に無効にするには、以下のように、そのデータセットの MasterLink プロパティの DisableScroll / EnableScroll メソッドを使用します。
qOrderDetails.MasterLink.DisableScroll;
try
qOrders.First;
while not qOrders.Eof do begin
if qOrders.FieldByName('OrderID').AsInteger = 100 then begin
qOrderDetails.ApplyMaster;
// read qOrderDetails dataset - it is synchronized with qOrders
end;
qOrders.Next;
end;
finally
qOrderDetails.MasterLink.EnableScroll;
end;
GUI アプリケーションでは、M/D の遅延同期が役に立つ場合があります。そのため、ユーザーがグリッド内をスクロールした場合、詳細データセットはすぐには更新されず、他のナビゲーションがない場合にのみ、少し遅れて更新されます。遅延同期を使用するには、詳細データセットの FetchOptions.DetailDelay を設定します。特定の詳細データセットに対して M/D の遅延同期を一時的に無効にして即時同期を使用するには、MasterLink プロパティの DisableDelayedScroll / EnableDelayedScroll メソッドを使用します。
デフォルトでは、状態変化、キーでないフィールドの値の変化、マスタ データセットの更新のどれが起こっても、詳細データセットの更新は行われません。このようになっているため、詳細データセットの余分な更新を避けることができます。アプリケーションで詳細データセットを常に更新すると想定する場合は FetchOptions.DetailOptimize を False に設定します。