更新コマンド生成(FireDAC)

提供: Appmethod Topics
移動先: 案内検索

データの編集(FireDAC) への移動

概要

データベース アプリケーションで以下のデータセット メソッドを呼び出す場合、更新モードは異なります。

また、データを更新する SQL コマンドは、FireDAC で自動的に生成されます。FireDAC の SQL コマンド ジェネレータは、データベースの ID フィールド、シーケンス、トリガ、特殊なデータ型(Oracle の BLOB/CLOB/BFILE など)を認識し、接続先の DBMS に応じて効率的な SQL コマンドを生成します。これにより、開発者が手動作成の SQL コマンドを使用しなければならないケースが少なくなります。FireDAC では、開発者は必ず TFDUpdateSQL を使用しなければならないわけではありませんが、これを使用すると、更新 SQL コマンドをオーバーライドできます。

たとえば、Oracle テーブル(ID フィールドがシーケンスからトリガで設定され、IMAGE が BLOB 型)に新しいレコードをポストする場合、FireDAC により、以下の SQL コマンドが生成されます。

 INSERT INTO OracleTab (NAME, DT, IMAGE)
 VALUES (:NEW_NAME, :NEW_DT, EMPTY_BLOB())
 RETURNING :NEW_ID, :NEW_IMAGE

1. FROM、INTO、UPDATE の各句

FireDAC では、SELECT ... FROM ... 文のメイン テーブル(最初のテーブル)を更新テーブル名として使用します。また、このテーブルは mkPrimaryKeyFields メタデータの取得にも使用されます。UpdateOptions.UpdateTableName を使用すると、更新テーブルを明示的に指定できます。これが必要なのは以下の場合です。

  • データセットが TFDStoredProc である。
  • TFDQuery に SELECT クエリが含まれていない。
  • FireDAC が更新テーブル名をクエリから正しく取得できない。
  • アプリケーションで更新を特定のテーブルにリダイレクトする必要がある。

2. WHERE 句

UpdateOptions.UpdateMode では、更新および削除をポストするための WHERE 句の生成を制御します。デフォルト値 upWhereKeyOnly の場合は、WHERE 句で一意識別列のみ使用され、更新行を効率的かつ安全に特定できます。一意識別列が指定されず、行を識別する列も見つからない場合、FireDAC では UpdateOptions.UpdateModeupWhereAll に切り替えます。WHERE 句に以下のようなフィールドが含まれている場合は、"行が見つかりません" というエラーが発生するおそれがあります。

  • DOUBLE 型、FLOAT 型、TIME 型、DATETIME 型のフィールドやその他の浮動小数点ベース フィールドの場合、値の比較で精度が落ちるおそれがあります。
  • テキスト フィールドに無効なエンコーディングや余分なスペースがある場合、比較に失敗するおそれがあります。
  • その他似たような障害が発生するおそれがあります。

そのような場合、アプリケーションでは以下の例外が発生します。

 [FireDAC][DApt]-400. Update command updated [0] instead of [1] record.

同様に、WHERE 句で指定されている列で行が一意に識別されない場合は、複数のレコードが更新される可能性があります。その場合、次のような例外が発生します。

 [FireDAC][DApt]-400. Update command updated [4] instead of [1] record.

これらの問題を解決するには、以下を検討します。

  • 正しい一意識別列を指定する。
  • 対応する TField.ProviderFlags プロパティから pfInWhere を取り除くことで、WHERE 句で使用されている一部のフィールドを無効にする。
  • UpdateOptions.CountUpdatedRecordsFalse に設定することで、これらのエラーが発生しないようにする。

メモ: (トリガも含まれている)SQL Server テーブルで上記の問題を回避するには、それらのトリガの冒頭で SET NOCOUNT ON が指定されていなければなりません。それが不可能な場合は、UpdateOptions.CountUpdatedRecordsFalse に設定します。

3. SET 句と VALUES 句

UpdateOptions.UpdateChangedFields を使用すると、UPDATE SET ... 句または INSERT VALUES ... 句に含まれるフィールドを制御できます。これを True に設定すると、変更されたフィールドのみこれらの句に含まれることになり、以下の役に立ちます。

  • 更新のポスト時のトラフィックを最小限に抑える。
  • 不必要な制約検証を避ける。
  • 余分なトリガ発生を避ける。
  • REDO ログの生成を最小限に抑える。

これを False に設定すると、これらの句にすべてのフィールドが含まれることになり、生成された SQL 文と同じものをすべての更新のポストに再利用して、SQL 文を準備するための DBMS 処理をできるだけ少なくするのに役に立ちます。

列への更新を無効にするには、対応する TField.ProviderFlags プロパティから pfInUpdate を取り除きます。

4. RETURNING と追加の SELECT

UpdateOptions.RefreshMode = rmOnDemand の場合は、列値の自動更新を制御できます。列値は、レコードの挿入後または更新後に DBMS により変更される可能性があります。レコードの挿入後に更新が必要な場合がある列は以下のとおりです。

  • 自動インクリメント列
  • データベース側で値が計算される列
  • デフォルト値のある列
  • 行を識別する列
  • タイムスタンプ列
  • トリガで更新される列

レコードの更新後に更新が必要な場合がある列は以下のとおりです。

  • データベース側で値が計算される列
  • タイムスタンプ列
  • トリガで更新される列

DBMS の機能によっては、以下のように追加の句/コマンドが生成され、更新する列の値を返します。

  • Oracle、Firebird、PostgreSQL -- RETURNING 句
  • DB2 -- SELECT ... FROM FINAL TABLE 句
  • SQL Server、SQL Anywhere、SQLite -- 追加の SELECT コマンドを含んだ SQL バッチ
  • その他の DBMS -- 追加の SELECT コマンド

5. 更新コマンドのキャッシング

UpdateChangedFieldsFalse に設定すると、パフォーマンスが向上する場合があります。また、UpdateOptions.FastUpdates プロパティなどの他のいくつかの設定と組み合わせて、追加クエリを避け、生成された更新コマンドをキャッシュできるようにすることで、更新のポスト時のパフォーマンスをさらに向上させることができます。

FastUpdates = True は以下と同等です。

関連項目