ローカル SQL(FireDAC)

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

コマンドの操作(FireDAC) への移動

概要

ローカル SQL 機能を使用すると、DB テーブルの代わりに TDataSet の下位クラスを使用して SQL コマンドを実行することができます。ローカル SQL は、SQLite データベースが基礎になっており、ほとんどの SQLite SQL ダイアレクトがサポートされています。TDataSet の名前(Name プロパティの値)または指定された名前がテーブル名として使われます。クエリ可能なデータセットは、ローカル SQL エンジンである TFDLocalSQL に登録しなければなりません。

読み取り操作や書き込み操作はすべて、TDataSet API とその拡張機能を使って行われます。このエンジンでは、FireDAC と非 FireDAC のデータセットをサポートしています。ローカル SQL は、FireDAC データセットを使用した場合の方が効率的です。あるいは、非 FireDAC データセットの場合には、IFDPhysLocalQueryAdapter インターフェイスをアダプタ クラスとして実装し、ローカル SQL エンジンに登録することができます。

ローカル SQL の適用方法には次のようなものがあります。

  • 異種クエリ(さまざまな DB から取得した結果セットをクエリ可能なデータセットに保持します)。
  • インメモリ データベース(TFDMemTables がデータセットの役割をします)。
  • 拡張オフライン モード。この場合、メイン DB にはアクセスできませんが、アプリケーションが SQL クエリを実行することはできます。
  • 移行の簡略化。アプリケーションでサードパーティの TDataSet オブジェクトを使用し、FireDAC API によってそのデータ ソースを扱うことができます。

構成

FireDAC は、SQLite ドライバをローカル SQL エンジンとして使用します。そのため、アプリケーションではまず、SQLite の "ローカル" 接続が必要です。これは、インメモリ接続のような、ファイルベースの読み書き接続でもかまいません。インメモリ接続の使用をお勧めします。セットアップは以下の手順で行います。

アプリケーションでは、データセットをローカル SQL エンジンに接続する必要があります。手順は以下のとおりです。

  • フォームに TFDLocalSQL コンポーネントをドロップします。
  • その Connection プロパティをローカル SQLite 接続オブジェクトに設定します。
  • データセットの Name プロパティを確認し、必要であれば値を割り当てます。このステップが必要なのは、コード内で動的にデータセットを作成する場合です。
  • FireDAC データセットの場合、TFDAdaptedDataSet.LocalSQL プロパティを TFDLocalSQL インスタンスに設定します。
  • あるいは、FireDAC と非 FireDAC データセットの両方を使用する場合には、TFDLocalSQL.DataSets コレクションを使用して、TDataSet とアダプタ(オプション)をローカル SQL エンジンに登録します。また、DataSets コレクションを使用すると、代替データセット名を指定することができます。

最後に、以下のオブジェクトをアクティブ化します。

  • ローカル SQLite 接続を有効化します。
  • TFDLocalSQL.ActiveTrue に設定してローカル SQL エンジンを有効化します。
メモ: アプリケーションで、同じ SQLite 接続に接続された基底データセットとローカル データセットを使用している場合には、その接続を使用しているいずれかのデータセットを開いたり実行したり準備する前に、明示的に接続を有効化する必要があります。そうでなければ例外が発生します。

あるいは、TFDLocalSQL.OnGetDataSet イベント ハンドラを使用して、データセットをローカル SQL エンジンに送信することができます。

ローカル接続とローカル SQL エンジンの両方がアクティブになると、関連するすべてのデータセットがエンジンに登録されます。新しいデータセットを関連付ける時に何かを開き直す必要はなく、データセットは自動的に登録されます。登録されると、データセットは開きます。TFDMemTable には、開く前に構造を定義しておかなければなりません。アプリケーションで大量のデータセットを登録する場合には、登録前にローカル SQL エンジンを非アクティブ化し、登録後にアクティブ化することをお勧めします。

アプリケーションで TFDLocalSQL.SchemaName をスキーマ プレフィックスに設定し、それを SQL クエリ内で使用することができます。複数の TFDLocalSQL を同じ接続に接続して使用することができますが、そのときにスキーマ名を指定してもしなくてもかまいません。ただし、1 つの SQLite 接続内では、それぞれの TFDLocalSQL.SchemaName が一意でなければなりません。スキーマ名によってデータセットを論理グループに整理することができます。スキーマ名を指定すると、SQL コマンド内でデータセットを <データセット名> または <スキーマ名>.<データセット名> として参照することができます。

必要であれば、アプリケーションで TFDLocalSQL.MultipleCursorsFalse に設定して、データセットの複製やコピーを避けることができます。SQLite では、カーソルを作成して、データセットを参照する SQL コマンドを実行します。TDataSet API では 1 つの位置しか保持できません。その制限を回避するために、FireDAC では TFDMemTable を使って FireDAC データセットを複製したり、非 FireDAC データセットを TFDMemTable にコピーします。データセットが 1 秒に 1 度しか使われないことが確かであれば、MultipleCursorsFalse に設定してパフォーマンスを向上することができます。単方向データセットが存在する場合には、MultipleCursorsFalse に設定することはお勧めできません。

クエリ実行

ローカル SQL クエリを実行するには、アプリケーションで TFDQuery/TFDCommand を使用し、Connection/ConnectionName をローカル SQLite 接続(TFDLocalSQL.Connection にも設定されているもの)に設定しなければなりません。これで、ローカルでない SQL 接続の場合と同様に SQL クエリを実行することができます。

クエリを処理している間、クエリ可能なデータセットは DisableControls によって無効化され、処理が完了すると有効化されます。データセットを有効なままにするには、TFDLocalSQL.DisableControlsFalse に設定します。 データセットを読み取る前に TFDLocalSQL.OnOpenDataSet イベント ハンドラが呼び出されます。

ローカル SQL エンジンでは SQLite SQL ダイアレクトをサポートしていますが、いくらか制限があります。TDataSet データ ソースの場合には、以下の SQL コマンドがサポートされていません。

  • ALTER TABLE ... ADD COLUMN。その代わりに、データセット構造を変更してください。
  • DROP TABLE。データセットは、ローカル SQL エンジンから切り離すと、自動的に(解放ではなく)削除されます。
  • CREATE INDEX/DROP INDEX。SQL インデックスの代わりにデータセット インデックスを使用してください。
  • CREATE TRIGGER/DROP TRIGGER。トリガの代わりにデータセット イベントを使用してください。

ローカル SQL エンジンでは、複数の結果セットを含むデータセットをサポートしていません。

ローカル SQL エンジンでは、INSERT/UPDATE/DELETE の SQL コマンドを、トランザクションおよびセーブポイントとしてサポートしています。また、対応する SQL コマンドは TDataSet API 呼び出しに変換されます。

ローカル SQL エンジンでは INSERT OR REPLACE をサポートしていますが、主キーまたは一意キーの制約の違反があると、置換対象レコードの検索に主キー フィールドしか使われません。さらに、INSERT OR REPLACE INTO <テーブル> (<フィールド リスト>) で一部のフィールドしか指定されていない場合、指定されていないフィールドは更新時に NULL 値になります。

互換性

ローカル SQL エンジンでは、TDataSet API を IFDPhysLocalQueryAdapter インターフェイスによって拡張して使用しています。FireDAC データセットはこのインターフェイスを実装しています。さらに、非 FireDAC データセットの場合に必要であれば、このインターフェイスを実装するクラスを作成し、そのインスタンスを TFDLocalSQL.DataSets[..].Adapter プロパティに割り当てることができます。

また、ローカル SQL 操作を実行するには、データセットが以下の要件を満たしている必要があります。

操作 要件
INSERT 必須:
  • Append メソッド。
  • Post メソッド。

任意:

  • PSGetKeyFields は主キー フィールドを返さなければなりません。
UPDATE 必須:
  • Edit メソッド。
  • Post メソッド。
  • Locate メソッド。

任意:

  • PSGetKeyFields は主キー フィールドを返さなければなりません。
DELETE 必須:
  • Delete メソッド。
  • Locate メソッド。

任意:

  • PSGetKeyFields は主キー フィールドを返さなければなりません。
ソート/ORDER BY 任意:
  • IFDPhysLocalQueryAdapter.Features に afIndexFieldNames が含まれている場合には、データセットのソートに IFDPhysLocalQueryAdapter.IndexFieldNames プロパティが使われます。
フィルタリング/WHERE 任意:
  • IFDPhysLocalQueryAdapter.Features に afRanges が含まれている場合には、データセットのフィルタリングに IFDPhysLocalQueryAdapter.SetRange メソッドが使われます。
  • IFDPhysLocalQueryAdapter.Features に afFilters が含まれている場合には、Filter プロパティも使われます。
セーブポイント 必須:
  • IFDPhysLocalQueryAdapter.Features に afCachedUpdates、afSavePoints が含まれている場合には、IFDPhysLocalQueryAdapter.Savepoint プロパティが使われます。
トランザクション 必須:
  • PSStartTransaction メソッド。
  • PSEndTransaction メソッド。


例 1

以下に示すのは、SQL Anywhere および Oracle のテーブルと FireDAC の TFDQuery を使用した異種クエリです。

// SQL Anywhere DB 内の "Orders" テーブルに対する接続とクエリをセットアップする
FDConnection1.ConnectionDefName := 'ASA_Demo';
FDConnection1.Connected := True;
FDQuery1.Connection := FDConnection1;
FDQuery1.SQL.Text := 'select * from Orders';
// データセットをローカル SQL エンジンにリンクする
FDQuery1.LocalSQL := FDLocalSQL1;

// Oracle DB 内の "Order Details" テーブルに対する接続とクエリをセットアップする
FDConnection2.ConnectionDefName := 'Oracle_Demo';
FDConnection2.Connected := True;
FDQuery2.Connection := FDConnection2;
FDQuery2.SQL.Text := 'select * from "Order Details"';
// データセットをローカル SQL エンジンにリンクする
FDQuery2.LocalSQL := FDLocalSQL1;

// SQLite のインメモリ接続をセットアップする
FDConnection3.DriverName := 'SQLite';
FDConnection3.Connected := True;
// ローカル SQL を SQLite 接続にリンクする
FDLocalSQL1.Connection := FDConnection3;
FDLocalSQL1.Active := True;

// 上記のデータセットに対して SELECT クエリを実行する
FDQuery3.Connection := FDConnection3;
FDQuery3.SQL.Text := 'SELECT * FROM FDQuery1 LEFT JOIN FDQuery2 ON FDQuery1.OrderID = FDQuery2.OrderID';
FDQuery3.Active := True;


例 2

以下に示すのは、ADO の TADOQuery と FireDAC の TFDQuery を使用した異種クエリです。

// "Orders" テーブルに対する接続とクエリをセットアップする
ADOQuery1.SQL.Text := 'select * from Orders';
// データセットをローカル SQL エンジンにリンクする
with FDLocalSQL1.DataSets.Add do begin
  DataSet := ADOQuery1;
  Name := 'Orders';
end;

// "Order Details" テーブルに対する接続とクエリをセットアップする
ADOQuery2.SQL.Text := 'select * from "Order Details"';
// データセットをローカル SQL エンジンにリンクする
with FDLocalSQL1.DataSets.Add do begin
  DataSet := ADOQuery2;
  Name := 'Order Details';
end;

// SQLite のインメモリ接続をセットアップする
FDConnection1.DriverName := 'SQLite';
FDConnection1.Connected := True;
// ローカル SQL を SQLite 接続にリンクする
FDLocalSQL1.Connection := FDConnection1;
FDLocalSQL1.Active := True;

// 上記のデータセットに対して SELECT クエリを実行する
FDQuery1.Connection := FDConnection1;
FDQuery1.SQL.Text := 'SELECT * FROM Orders o LEFT JOIN "Order Details" od ON o.OrderID = od.OrderID';
FDQuery1.Active := True;

例 3

以下のデモを参照してください。

  • 複数の DBMS にまたがったクエリ: FireDAC\Samples\Comp Layer\TFDLocalSQL\xDBMS
  • インメモリ データベース: FireDAC\Samples\Comp Layer\TFDLocalSQL\InMemDB

関連項目