第26回 エンバカデロ・デベロッパーキャンプ【A2】Delphi/C++Builderテクニカルセッション

はじめてのFireDAC
2013年9月13日

田中 芳起

1

Ver.1.0.6
http://www.embarcadero.com/jp

自己紹介
会社：株式会社三菱電機ビジネスシステム

ビジコン

・三菱電機100%出資(4億円)
・1973年12⽉設⽴、創⽴40年
・中堅・中⼩企業向けソフトウェアの開発・販売
・http://www.melb.co.jp/

名前：⽥中 芳起（たなか よしき）

嶋 正利

・会社では、PMO (Project Management Office) を担当
・Delphiとは 1.0US版 からの付き合い
・ホームページ : http://www.avsoft.jp/: http://avsoft.typepad.jp/blog/
・ブログ
・Facebook : https://www.facebook.com/yoshiki.tanaka.942/

2

http://www.embarcadero.com/jp

プライベートの紹介
コンポーネントの開発・公開
・SuperEdit （⼊⼒系コンポーネント）・SuperGrid （グリッド・コンポーネント）
・⼤⼿コンビニのシステムで使⽤されている

3

http://www.embarcadero.com/jp

プライベートの紹介
統合型開発支援ツールの開発・公開
・Oracleアプリケーション開発⽀援
・Guiによるデータベース管理機能・統合型開発⽀援ツール
・オラクル社のOCI*1を使⽤した⾼速接続を実現

OCI ラッパー・
コントロール※ Facebookページで情報発信しています*1 OCI(Oracle Call Interface)は、Oracle社が提供するAPIです4

http://www.embarcadero.com/jp

アジェンダ BDEのおさらい• BDEとは?
• BDE(Borland Database Engine)の構造• データベースコンポーネント• コンポーネント内ではBDEにどうアクセスしているか?
• BDE環境設定ユーティリティ(BDE Administrator)• BDEの現状• BDEの抱える課題
 BDEからの移⾏• BDEから移⾏するための選択肢• BDEから移⾏する「新たな」選択肢
 FireDACについて• FireDACとは?
• FireDACを使⽤するメリットは･･• FireDACアプリケーションの構造• データベースドライバの対応表• BDEとFireDAC 主要コンポーネントの⽐較• データベースクラスの継承関係
5

http://www.embarcadero.com/jp

アジェンダ TADConnectionコンポーネント• プロパティの⽐較• 接続の設定･･Oracleの場合• トランザクション管理• ログイン制御• データ型のマッピングを変更する• Connection Editor でSQLを実⾏する• SQL⽂の実⾏• DBMSのサーバ／クライアントのバージョン番号を求める
 TADPhysXXXXDriverLinkコンポーネント• TADPhysXXXXDriverLinkとは?
• データベースとドライバの対応表
 TADGUIxWaitCursorコンポーネント• TADGUIxWaitCursorとは?
• BDEアプリケーションからの移植• FireMonkeyアプリケーションでの注意点

6

http://www.embarcadero.com/jp

アジェンダ TADTableコンポーネント• プロパティの⽐較• カーソルを移動する• データの更新• レコードの検索• Bookmark を利⽤する• データコントロールへの描画抑制• ⾏の選択• 項⽬の参照 TFieldコンポーネント• TFieldコンポーネントとは?
• プロパティの⽐較• TFieldのプロパティ／イベントを設定する• 特定フィールドを⾮表⽰にする• その他プロパティの設定を変更する• 計算項⽬を追加する• LOB(Large OBject)データの登録／保存7

http://www.embarcadero.com/jp

アジェンダ TADQueryコンポーネント• プロパティの⽐較• SQL⽂を設定する• 静的問い合わせ• 動的問い合わせ• ⼤量のＤＭＬを⾼速に実⾏する• 複数SQLのデータセットを利⽤する• データベース例外を捕捉する• マクロを使う• データセットの状態を調べる• 結果セットの変更
 TADUpdateSQLコンポーネント• キャッシュアップデート• プロパティの⽐較• キャッシュアップデートの設定• 更新情報のサーバーへの書き込み• OnUpdateRecord イベント
• OnUpdateError イベント

8

http://www.embarcadero.com/jp

アジェンダ TADStoredProcコンポーネント• プロパティの⽐較• PROCEDUREの実⾏• FUNCTIONの実⾏• PACKAGEの実⾏
 まとめ
• まとめ
• 参考情報9

http://www.embarcadero.com/jp

はじめてのFireDAC
BDEのおさらい10

http://www.embarcadero.com/jp

BDEとは?
・BDEは、RDBMSとDelphi(C++Builder)アプリケーションをつなぐミドルウェア
・Paradox、dBASEのデータベースエンジンとして使われている・ローカルデータベース以外にも、サーバーデータベースにも透過的にアクセスが可能
・BDE APIを使⽤して直接BDEを使⽤することが可能

クライアント・アプリケーション
BDE
Oracle⽤SQL-Linkドライバ
Oracleクライアントライブラリ
OCI.dlltnsnames.ora

DB
Oracle 8i

11

http://www.embarcadero.com/jp

BDE(Borland Database Engine)の構造
ParadoxforWindows

Borland
C++

dBASE
for
Windows

Delphiアプリケーション
BDE API (IDAPI)BDE (Borland Database Engine)

SQL Link
ドライバ

ParadoxDriverdBASE
DriverASCIIInterBase, Oracle, Informix, Sybase/MS-SQL Server
DriverODBC
Driver

TCP/IP, SPX/IPXParadox

dBASE

ローカル
データベース12

http://www.embarcadero.com/jp

Text
RDBMS

InterBase/Oracle/Informix/
Sybase/MS-SQL Serverデータベースコンポーネント
Data Accessコンポーネント

Data Controlコンポーネント

BDEコンポーネント

TDBGrid
TTableTDataSource

TDBNavigator
TDBText

RDBMS

B
D
E

TQueryTDataSource

TDBEdit
TDBMemo
TDBImage：13

http://www.embarcadero.com/jp

コンポーネント内ではBDEにどうアクセスしているか?
次のソースコードは、TTableコンポーネントの「DeleteTableメソッド」の内部処理
procedure TTable.DeleteTable;
begin
CheckInactive;
SetDBFlag(dbfTable, True);
try
Check(DbiDeleteTable(DBHandle, NativeTableName, GetTableTypeName));finally
SetDBFlag(dbfTable, False);
end;
end;
メソッド内部で｢DbiDeleteTable｣というIDAPI関数を呼び出して、テーブルの削除を実現している

14

http://www.embarcadero.com/jp

BDE環境設定ユーティリティ(BDE Administrator)

データベースタブ・BDEエリアス*1の設定・管理
環境設定
・ドライバ情報の管理
15

http://www.embarcadero.com/jp*1 BDEエリアス
データベース接続に必要な情報をまとめて管理するBDEオブジェクト

BDEの現状
BDEは2002年に開発・保守が終了
・不具合があっても修正パッチの提供はされていない
BDEの最新バージョンは 5.2
・Delphi 7/C++Builder 6以降、BDEのバージョンは更新されていない
・現在のDelphi/C++Builder製品に付属するBDEは、あくまで過去の資産保守⽤
動作保証プラットフォームは Windows XPまで
・Windows XP以降にリリースされたOSバージョンは動作保証がされていない（例えば、Windows Vista/7/8、Windows2003/2008 Serverなど）

16

http://www.embarcadero.com/jp

BDEの抱える課題
近年の(PC)ハードウェア構成にマッチしない

・4G越えのHDDの空き容量が正しく認識されない・マルチコア／プロセッサ搭載のPC上での動作が不安であるOSの新機能に対しては、Vista以降対応していない

・UAC(User Account Control)
・ASLR(Address Space Layout Randomization)によるアドレス衝突が発⽣・BDEアプリを複数同時起動した場合、初期化エラーが発⽣することがある

対応しているデータベースのバージョンが古い

・Oracle(8.1.6)、MS-SQL Server(7.0)、DB2(5.0)･･
・詳細は以下のURLで確認
http://support.embarcadero.com/jp/article/36002

とにかく配布が⾯倒

・アプリケーションを配布する場合、BDEとSQL-Linkも⼀緒に配布する必要がある
・環境設定ユーティリティでBDEやエリアス設定が必要
・BDEのバージョンやエリアスの重複等、実⾏環境に依存する

最近のニーズに適合したアプリケーションが作成できない

・64ビット化、Unicode対応、クロスプラットフォーム、マルチデバイス･･

17

http://www.embarcadero.com/jp

はじめてのFireDAC
BDEからの移⾏

18

http://www.embarcadero.com/jp

BDEから移行するための選択肢
BDE以外で、従来のDelphi/C++Builderから
標準で利⽤可能なデータベースフレームワークの種類
 dbExpress dbGO(ADO/OLEDB)
 IBExpress (InterBase専⽤)
移⾏の壁
データアクセスアーキテクチャの違い

・カーソルの違い（サーバーサイドカーソル／クライアントサイドカーソル）・フィルタの指定有無／条件

BDE DataSetとの⾮互換が多く、移植性が悪い

・dbExpressのTSQLTable(Query)とBDEコンポーネントのメソッドやプロパティが異なる

実⾏パフォーマンスが出ない・BDEでは1秒で済んでいたものが、dbExpressやdbGOで21秒もかかった19

http://www.embarcadero.com/jp

BDEから移行する「新たな」選択肢
BDE以外で、Delphi/C++Builderから利⽤可能なデータベース・フレームワークの新定番
 dbExpress dbGO(ADO/OLEDB)
 IBExpress (InterBase専⽤)
新たな選択肢！

20

http://www.embarcadero.com/jp

はじめてのFireDAC
FireDACについて

21

http://www.embarcadero.com/jp

FireDACとは?
・AnyDACの｢Embacadero版｣
・ユニバーサルデータアクセスが可能な、⼀体化されたコンポーネント群

Oracle/MS-SQL Server/DB2/MySQL/PostgreSQL/InterBase/Firebird/SQLite/SQL Anywhere/Advantage DB/
Access/Informix/DataSnapなどに⾼速なネイティブアクセスが可能
対応ドライバは、次のURLを参照
http://docs.embarcadero.com/products/rad_studio/firedac/frames.html?frmname=topic&frmfile=Databases.html

・DelphiおよびC++Builder向け

RAD Studio/ Delphi/ C++Builder XE4、XE5

詳しくは、次のURLを参照
http://www.embarcadero.com/jp/products/rad-studio/firedac-faq

・マルチデバイス

Win32, Win64, Mac OS X, iOS, Android

・ハイパフォーマンス

BDEと同等、それ以上のデータアクセススピード

・共通化されたAPI

マクロ機能を使ってSQLの⽅⾔や微妙な違いを吸収修正可能なデータマッピング機能によるデータ型の統⼀化

22

http://www.embarcadero.com/jp

FireDACを使用するメリットは･･
BDEとの互換性が⾼い

・データアクセスアーキテクチャが類似している
・従来のBDE DataSetとの互換性を備えたDataSetクラスがある
・CachedUpdatesモードも利⽤可能

ハイパフォーマンス・BDEと同等、それ以上のデータアクセススピード

配布が簡単

・専⽤のデータベースドライバやインストーラが不要

Professionalエディションでもリモート接続が可能

23

http://www.embarcadero.com/jp

FireDACアプリケーションの構造
・FireDACアプリケーションは、3層構造・⾚枠がFireDACコンポーネント本体
・開発には32ビットのクライアントライブラリが必須

24

http://www.embarcadero.com/jp

注意！

BDEとFireDAC 主要コンポーネントの比較
BDE

FireDAC

解説

TDatabase

TADConnection○

TSession

TADManager

TTableTADTable○

TQueryTADQuery○

TStoredProc

TADStoredProc○

TUpdateSQLTADUpdateSQL○

TBatchMove

TADDataMove－

TADPhysXXXXDriverLink○－

TADGUIxWaitCursor○※ BDEのコンポーネント名にAnyDACの「AD」を付加したネーミング※ BDEの対応は、次のサイトを参照
http://docs.embarcadero.com/products/rad_studio/firedac/frames.html?frmname=topic&frmfile=index.html[参照先] Contents > Migrating BDE applications > BDE name counterparts25

http://www.embarcadero.com/jp

データベースクラスの継承関係
TDataSet から派⽣！

TComponent
TCustomConnection
TDataSet

TADDataSet

TADCustomConnection

TADAdaptedDataSet
TADRdbmsDataSet
TADCustomQuery

TADComponent

TADConnection

TADTable
TADQuery

TADCustomStoredProc

TADStoredProc

TADCustomManager

TADManager

TADCustomUpdateObject

TADUpdateSQLTADDataMove

TFieldTDataSource26

http://www.embarcadero.com/jp

XXX：FireDACXXX：Delphi標準

はじめてのFireDAC
TADConnectionコンポーネント

27

http://www.embarcadero.com/jp

プロパティの比較
BDE (TDatabase)

FireDAC (TADConnection)

備考AliasName

ConnectionDefName

エリアスを指定

DatabaseName

ConnectionName

アプリケーション内で参照するときのエリアス名Connect

Connect

Open/Closeメソッドと等価

ParamsParams

接続パラメータを保持

DriverName

DriverName

DriverIDを指定 *1

KeepConnection

KeepConnection

True:接続を保持（既定値）
ResourceOptionsに移動－

LoginDialog

TADGUIxLoginDialogコンポーネントを指定

LoginPrompt

LoginPrompt

True:ログインダイアログボックスの表⽰

SessionName－

TADManagerコンポーネントで指定

TransIsolation－

アイソレーション(分離)レベルを指定
TxOptions.Isolationプロパティで指定*1 DriverIDは、次のURLで確認
http://docs.embarcadero.com/products/rad_studio/firedac/frames.html?frmname=topic&frmfile=Databases.html

28

http://www.embarcadero.com/jp

接続の設定･･Oracleの場合 (1/2)
Connection Editorで設定

オブジェクトインスペクタの下にある ｢Connectin Editor ...｣ をクリックする
Driver ID:

リストから接続するサーバーのIDを指定選択すると既定値が、パラメータ欄に表⽰される

Connection Definition Name:（必須ではない）
エリアス名をリストから選択
エリアスは ｢FireDAC Explorer｣ で設定

Database:｢TNSNames.ora｣ に設定されている「ネットサービス名」を⼊⼒

User_Name/Password:
ユーザ名とパスワードを⼊⼒

AuthMode:

接続モードをリストから選択※他のパラメータは、適宜設定して下さい※⼊⼒後、｢Test｣ボタンを押して接続を確認

29

http://www.embarcadero.com/jp

接続の設定･･Oracleの場合 (2/2)
コードで設定実⾏時に接続に必要なパラメータをコードで指定する（⾚字の部分）
trywith ADConnection1 do
begin// 接続パラメータのセット
Params.Add('DriverID=Ora');Params.Add('Database=ORCL');
Params.Add('User_Name=SCOTT');
Params.Add('Password=TIGER');
Params.Add('AuthMode=Normal');
// 接続
Open;
end;
exceptMessageDlg(‘データベースと接続できません！ ', mtError, [mbOK], 0);end;※セキュリティには⼗分な配慮をして下さい30

http://www.embarcadero.com/jp

トランザクション管理
Delphiでは｢暗黙トランザクション｣と｢明⽰トランザクション｣の2種類がサポートされている
ここでは明⽰トランザクションを説明します

プロパティ／メソッド

説明

InTransaction

True: トランザクションが進⾏中StartTransaction指定されたアイソレーションレベル*1でトランザクションを開始

Commit

変更内容をすべてコミットし、トランザクションを終了

Rollback

変更内容を取り消し、トランザクションを終了

begin
if not ADConnection1.InTransaction then
ADConnection1.StartTransaction;try･･･ トランザクション中のDML実⾏// トランザクションをコミット
ADConnection1.Commit;
except// トランザクションをロールバック
ADConnection1.Rollback;raise;
end;
end;*1 アイソレーションレベルはTxOptions.Isolationプロパティで指定します

31

http://www.embarcadero.com/jp

ログイン制御
標準のログインダイアログボックス

LoginPrompt が True (既定値)だと標準のログインダイアログボックスが表⽰される

ログインダイアログボックスのカスタマイズ

FormにTADGUIxLoginDialogコンポーネントを配置し、TADConnectionコンポーネントのLoginDialogプロパティを指定すると、ログインダイアログボックスを変更することができる

32

http://www.embarcadero.com/jp

データ型のマッピングを変更する (1/3)
・FireDACのマッピングルールは dbExpress に類似している・FireDACではマッピングルールの変更が可能（dbExpress では不可）・マッピングルールは TADMapRuleクラス で定義・管理される
・マッピングは接続（セッション）単位、データセット単位で設定することができる
・マッピングルールを変更することにより、より効率的な型変換が可能となる[EMPテーブル][TFieldコンポーネント]

型変換

TBCDField
TStringField
TStringField
TBCDField
TDateTimeField
TBCDField
TBCDField
TBCDField※OracleのNUMBER型が TBCDField (2進化10進数項⽬) にマッピングされてしまう

33

http://www.embarcadero.com/jp

データ型のマッピングを変更する (2/3)
・Connection Editorで設定する
・Options タブの「Data Mapping Rules」を開く
・｢Ignore inherited rules｣にチェックを付け、定義の設定を有効にする

プロパティ

34

説 明

SourceDataType

ソース・データの型（タイプ）を指定

TargetDataType

変換後のデータの型（タイプ）を指定

PrecMin/PrecMax

数字精度（precision）の範囲を指定

ScaleMin/ScaleMax

数字スケール（⼩数点以下の桁数）の範囲を指定

SizeMin/SizeMax

⽂字列⻑の範囲を指定

NameMask

カラム名を指定http://www.embarcadero.com/jp

データ型のマッピングを変更する (3/3)
マッピングルールは、コードでも設定できるwith ADConnection1.FormatOptions do
begin//⾃分⾃⾝のマッピング・ルールを使う
OwnMapRules := True;//ルールの定義 ①
with MapRules.Add do
begin
PrecMin := 10;
PrecMax := 10;
ScaleMin := 0;
ScaleMax := 0;
SourceDataType := dtFmtBCD;
TargetDataType := dtInt32;
end;//ルールの定義 ②
with MapRules.Add do
begin
NameMask := '%ID';
TargetDataType := dtInt32;
end;
end;

［ルールの解説］①数字フィールドの精度が10桁の数値項⽬は、BCD(2進化10進数)から｢32ビットの整数型｣で処理する②フィールド名に｢ID｣の⽂字が含まれている数値項⽬は、｢32ビットの整数型｣で処理する
35

http://www.embarcadero.com/jp

Connection Editor でSQLを実行する
SQL Script タブで、⼀時的なSQL⽂の実⾏が可能

36

http://www.embarcadero.com/jp

SQL文の実行
ExecSQLメソッドを使⽤するとTADConnectionコンポーネントでもSQL⽂の実⾏が可能
const
strSQL = 'CREATE TABLE TABLE1(NO NUMBER(4) NOT NULL, NAME VARCHAR2(10), KINGAKUNUMBER(7,2))';
begin
try
// SQL⽂の実⾏
ADConnection1.ExecSQL(strSQL);
exceptMessageDlg(‘SQLの実⾏に失敗しました！ ', mtError, [mbOK], 0);
end;
end;

37

http://www.embarcadero.com/jp

DBMSのサーバ／クライアントのバージョン番号を求める
TADConnectionコンポーネントの ConnectionMetaDataIntf プロパティ で取得する
function TDataModule1.GetDBMSversion: String;
const
StrVer = 'Client Version: %.10d / Server Version: %.10d';varoMetaIntf: IADPhysConnectionMetadata;
begin
oMetaIntf := ADConnection1.ConnectionMetaDataIntf;try
Result := Format(StrVer, [oMetaIntf.ClientVersion, oMetaIntf.ServerVersion]);finallyoMetaIntf:= nil;
end;
end;

[実⾏結果]

38

http://www.embarcadero.com/jp

はじめてのFireDAC
TADPhysXXXXDriverLinkコンポーネント

39

http://www.embarcadero.com/jp

TADPhysXXXXDriverLinkとは?
・FireDACで新たに追加されたコンポーネント
・接続するデータベースに対応したドライバ(TADPhysXXXXDriverLink)が必要
・ドライバとなっているが中⾝はPascalで書かれたインターフェイス
・ドライバは実⾏モジュールに組み込まれる・FireDACアプリケーションでは、1つは配置することが必要※配置しないで実⾏すると次のエラーが表⽰される

40

http://www.embarcadero.com/jp

データベースとドライバの対応表
データベース

FireDAC

OracleTADPhysOracleDriverLink

DB2

TADPhysDB2DriverLink

MS SQL Server

TADPhysMSSQLDriverLink

InterBase／FireBird

TADPhysIBDriverLink

PostgreSQL

TADPhysPgDriverLink

MySQL

TADPhysMySQLDriverLink

Sybase ASE

TADPhysODBCDriverLink

SQLiteTADPhysSQLiteDriverLink

MS Access

TADPhysMSAccessDriverLink

ODBCブリッジドライバ

TADPhysODBCDriverLink

dbExpressブリッジドライバ

TADPhysDBXDriverLink

DataSnap

TADPhysDataSnapDriverLink※ 対応ドライバは、次のURLを参照
http://docs.embarcadero.com/products/rad_studio/firedac/frames.html?frmname=topic&frmfile=Databases.html
41

http://www.embarcadero.com/jp

はじめてのFireDAC
TADGUIxWaitCursorコンポーネント

42

http://www.embarcadero.com/jp

TADGUIxWaitCursorとは?
・FireDACで新たに追加されたコンポーネント
・IADGUIxWaitCursorインタフェースを実現するためのコンポーネント
・Forms、FMX、および Consol プログラムで使⽤することができる・FireDACアプリケーションでは、1つは配置することが必要※配置しないで実⾏すると次のエラーが表⽰される

43

http://www.embarcadero.com/jp

BDEアプリケーションからの移植
・BDEで時間の掛かる処理は、次の様なカーソルの制御が⼀般的
Screen.Cursor := crSQLWait;try......
finally
Screen.Cursor := crDefault;
end;

・FireDACでは次の様なコードに置き換えることもできる（必須ではない！）
uses
uADStanFactory, uADGUIxIntf;......
var
oWait: IADGUIxWaitCursor;
begin......
ADCreateInterface(IADGUIxWaitCursor, oWait);
oWait.StartWait;try......
finallyoWait.StopWait;
end;
end;

44

http://www.embarcadero.com/jp

FireMonkeyアプリケーションでの注意点
・TADGUIxWaitCursorのProviderプロパティが「Form」に設定されているとエラーが発⽣する

・Providerプロパティは次のように設定




45

FireMonkeyアプリケーション ： FMX： FormVCLアプリケーション
コンソールアプリケーション ： Console

http://www.embarcadero.com/jp

はじめてのFireDAC
TADTableコンポーネント

46

http://www.embarcadero.com/jp

プロパティの比較
BDE (TTable)

47

FireDAC (TADTable)

備考

ActiveActiveOpen/Closeメソッドと等価

AutoCalcFields

AutoCalcFields

True:OnCalcFields イベントの発⽣。
計算項⽬の計算を意図的に⽌めたいときはFalseにする

Bof

Bof

True:カーソルがデータセットの先頭にあるCachedUpdates

CachedUpdates

True:キャッシュアップデートが使⽤可能

DatabaseName

ConnectionName

アプリケーション内で参照するときのエリアス名

Eof

Eof

True:カーソルがデータセットの最後にある

Exclusive

Exclusive

True:排他的にテーブルをアクセスする

IndexFieldNames

IndexFieldNames

テーブルのインデックスフィールドを表⽰

IndexName

IndexName

テーブルの⼆次インデックスをリストから選択

MasterFields

MasterFields

リンクする項⽬をセミコロンで区切って指定

MasterSource

MasterSource

テーブル同⼠をリンクする場合、リンクするテーブルのTDataSourcを指定

TableName

TableName

テーブル名を指定

ReadOnly

ReadOnly

True:読み取り専⽤
UpdateOptionsオプションに移動

UpdateMode

UpdateMode

更新レコードの検索⽅法をリストから選択
UpdateOptionsオプションに移動

http://www.embarcadero.com/jp

カーソルを移動する
データセット上でレコード間の移動を⾏う場合、次のメソッドを使う
メソッド

機

First

先頭⾏へ移動する

Last

最終⾏へ移動する

Next

次の⾏へ移動する

Prior

１つ前の⾏へ移動する

MoveBy(n)n⾏分、⾏を移動する
移動は、現在の⾏を基準にして相対的に⾏われる[MoveByの使⽤例]
procedure TForm1.Button1Click(Sender: TObject);
begin
ADTable1.MoveBy(-10); // ⾏を10⾏戻す
ADTable1.MoveBy(20); // ⾏を20⾏進める
end;

48

能

http://www.embarcadero.com/jp

データの更新
データセットのレコードを操作するメソッドには次のものがある
メソッド

機

Edit

データセットを編集状態にする

Append

最終⾏にレコードを追加して挿⼊状態にする

Insert

現在の⾏にレコードを追加して挿⼊状態にする

Post

データセットに変更を登録しデータセットを参照状態にする

Cancel

変更を取り消しデータセットを参照状態にする

ClearFields

現在のレコードのすべての項⽬の内容を消去する

Delete現在の⾏を削除して、参照状態にする

能[⾏の挿⼊]
procedure TForm1.Button1Click(Sender: TObject);var
FldName: array[0..2] of TField;
beginwith ADTable1 do
begin// 各フィールドのTFieldを取得
FldName[0] := FindField('NO');// コードFldName[1] := FindField('NAME');// 商品名FldName[2] := FindField(‘KINGAKU’); // ⾦ 額// 空の⾏を挿⼊
Insert;// 各フィールドに値をセット
FldName[0].AsInteger := 001;
FldName[1].AsString := 'Delphi XE4‘;
FldName[2].AsCurrency := 50000;// データの登録
Post;
end;
end;

49

http://www.embarcadero.com/jp[次の様に書き換えることもできる]with ADTable1 do
begin// 各フィールドの値を指定して⾏を挿⼊する
InsertRecord([001, 'Delphi XE4', 50000]);end;レコードの検索
レコードの検索には、次のメソッドを使う
メソッド

機

GotoKey

キーバッファに指定された値の位置へテーブルカーソルを移動する

GotoNearest

キーバッファに指定された値以上の値を持つレコードにテーブルカーソルを移動する

FindKey

引数に配列で指定された値に⼀致するレコードを検索し、テーブルカーソルを移動する

FindNearest

引数で指定された検索値以上の値を持つレコードにテーブルカーソルを移動する[FindKeyの使⽤例]
procedure TForm1.Button1Click(Sender: TObject);begin
if (ADTable1.FindKey([7900]) = True) thenShowMessage('EMPNO:7900へ移動')
else
ShowMessage('EMPNO:7900のレコードが⾒つかりません。');
end;

50

能

http://www.embarcadero.com/jp

Bookmark を利用する
Bookmarkと呼ばれる⽬印を付けて、データセットの特定の位置に移動することができる
メソッド

機 能

BookmarkValid

ブックマークが正しくレコードを指しているかどうかを判定する

CompareBookmark

２つのブックマークが等しいかどうかを判定する

GetBookmark

カレントレコードにブックマークを付け、それを返す

GotoBookmark

ブックマークで指定したレコードへカーソルを移動する

FreeBookmark

不要になったブックマークを解放する

procedure TDataModule1.DoSomething(const Tbl: TADQuery);varBookmark: TBookmark;begin
Bookmark := Tbl.GetBookmark;Tbl.DisableControls;try
Tbl.First;
while not Tbl.Eof do
begin// 処理記述
Tbl.Next;
end;
finally
Tbl.GotoBookmark(Bookmark);
Tbl.EnableControls;
Tbl.FreeBookmark(Bookmark);
end;
end;

51

http://www.embarcadero.com/jp

データコントロールへの描画抑制
カーソル移動を頻繁に⾏うと再描画処理が頻繁に発⽣し、レスポンスが低下する
それを抑制するには、次のメソッドを使⽤
メソッド

機DisableControls

TDataSourceコンポーネントとのリンクを解除する

EnableControls

TDataSourceコンポーネントと、再度リンクする

procedure TForm1.Button1Click(Sender: TObject);
beginwith ADQuery1 do
begin
DisableControls;
tryFirst;
while not Eof do
begin･･･ データセット操作
Next;
end;
finally
EnableControls;
end;
end;
end;

52

能

http://www.embarcadero.com/jp

行の選択
⾏の選択を⾏うためにはデータセットのフィルタ制御を使⽤する
プロパティ／イベント

機能Filter

フィルタ⽂字列を指定する

Filtered

True: フィルタ有効

OnFilterRecord

フィルタ有効時(True)に、データセット内でアクティブなレコードが変わるたびに発⽣[プロパティで設定]
with ADTable1 do
begin
Filter := 'JOB=''SALESMAN''';
Filtered := True;
Open;
end;
[イベントで設定]
ADTable1.Filtered := True;：
procedure TForm1.ADTable1FilterRecord(DataSet: TDataSet; var Accept: Boolean);
begin
Accept := DataSet['JOB'] = 'SALESMAN';
end;

53

http://www.embarcadero.com/jp

項目の参照データセットは、列情報を項⽬コンポーネント(TField)として管理される

参照は、項⽬コンポーネントのFieldsプロパティやFieldByNameメソッドを使⽤する
プロパティ／メソッド機

Fields指定された項⽬順のTFieldコンポーネントを返す

FieldByName

指定された項⽬のTFieldコンポーネントを返す[Fieldsプロパティを使⽤]
with ADTable1 do
begin
S1 := Fields[0].AsString;S2 := Fields[1].AsString;end;[FieldByNameメソッドで設定]
with ADTable1 do
begin
S1 := FieldByName('EMPNO').AsString;S2 := FieldByName(‘ENAME’).AsString;
end;

54

能

http://www.embarcadero.com/jp

はじめてのFireDAC
TFieldコンポーネント

55

http://www.embarcadero.com/jp

TFieldコンポーネントとは?
・レコード内のフィールドにアクセスするためのコンポーネント
・TADTable/TADQuery がアクティブになったとき⾃動で⽣成される（動的⽣成）
・設計時に作成することも可能（静的⽣成）･･･「永続化フィールド」ともいう[DB][TFieldコンポーネント][EMPテーブル]
EMPNO
ENAME
JOB
MGR
HIREDATE
SAL
COMM
DEPTNO56

http://www.embarcadero.com/jp

NUMBER(4)VARCHAR2(10)VARCHAR2(9)NUMBER(4)DATE
NUMBER(7,2)
NUMBER(7,2)
NUMBER(2)⽣成

TBCDField
TStringField
TStringField
TBCDField
TDateTimeField
TBCDField
TBCDField
TBCDField

主要プロパティ／メソッド
FireDACでは、プロパティ・イベント・メソッドが⼤幅に追加されている
プロパティ

説

明

Alignment

データの表⽰⽅法をリストから選択

DisplayFormat

数値フィールドの表⽰形式を指定 (#,##0)

DisplayLabelTDBGridの列ヘッダーに表⽰するテキストを指定

DisplayWidth

コントロールが使⽤する⽂字数を指定

EditFormat *1

数値フィールドの⼊⼒形式を指定 (#,##0)

FieldName

物理的な列の名前が表⽰されている

Index

TFieldコンポーネントの順番を指定

MaxValue

BCD *2 型項⽬の最⼤値の上限を指定

MinValue

BCD 型項⽬の最⼩値の下限を指定

VisibleTDBGridに表⽰されるかどうかを指定

OnGetText

フィールドのDisplayTextまたはTextプロパティが参照された
ときに発⽣

OnSetText

Textプロパティに値がセットされたときに発⽣

OnValidate

データがレコード バッファに書き込まれる直前に発⽣*1 EditFormat : 設定されていない場合は、DisplayFormatが使⽤される

57

http://www.embarcadero.com/jp

TFieldのプロパティ／イベントを設定する
・TADTable/TADQuery コンポーネント上で右クリックし「フィールド エディタ…」を選択・表⽰されたフィールドエディタ内で右クリックし「すべてのフィールドを追加」をクリック
・フィールドを選択し、「オブジェクト インスペクタ」でプロパティ／イベントを設定する※フィールドエディタに表⽰されていない項⽬は、アプリケーションで使⽤できない[フィールド エディタ]

すべてのフィールドを追加（永続化フィールドの⽣成）

58

http://www.embarcadero.com/jp

フィールドを選択特定フィールドを非表示にする
TDBGridで特定フィールドを⾮表⽰にする場合は、次のいずれかの⽅法を使います・フィールドエディタから該当項⽬を削除する（永続化フィールドから削除する）
or・フィールドのVisibleプロパティをFalseにする

HIREDATE/SAL/COMM を⾮表⽰に設定！

59

http://www.embarcadero.com/jp

OnGetText イベント
フィールドの値によって表⽰内容を変更する

・請求区分が「0」なら「未」、以外なら「済」と表⽰するようにコードを記述
procedure TForm1.ADQuery1SEIKYUKBNGetText(Sender: TField; var Text: string;
DisplayText: Boolean);begin
if Sender.AsInteger = 0 then
Text := '未' else Text := '済';
end;

60

http://www.embarcadero.com/jp

その他プロパティの設定を変更する
項⽬の表⽰順を変更する

フィールドエディタでドラッグ＆ドロップで順番を変更する

TDBGridの⾒出しを変更したい

項⽬コンポーネントのDisplayLabelで変更する

TDBGridの列の表⽰幅を変更したい

項⽬コンポーネントのDisplayWidthで変更する

61

http://www.embarcadero.com/jp

計算項目を追加する
・フィールドエディタで右クリックし「フィールド新規作成...」を選択
・各項⽬を設定し［OK］を押下

設定はDataSet側
で⾏う!

・計算式はOnCalcFieldsイベントで定義
procedure TForm1.ADTable1CalcFields(DataSet: TDataSet);
begin
ADTable1KINGAKU.Value := ADTable1SURYO.Value + ADTable1TANKA.Value;
end;

62

http://www.embarcadero.com/jp

LOB(Large OBject)データの登録／保存 (1/2)
BLOB*1 データのテーブルへの登録とファイルへの保存⽅法は次の様になる
・BLOB格納⽤のテーブルを⽣成する
CREATE TABLE LOBTABLE(
BlobName
VARCHAR2(20),BlobDateTime DATE,
BlobEntity
BLOB)

・BLOBデータをテーブルへ登録する

BLOBフィールドをTBlobFieldでキャストし、LoadFromFile メソッドで登録する
procedure TForm1.Button1Click(Sender: TObject);
beginwith ADQuery1 do
begin
Open;
Append;Fields[0].AsString := 'Data1';
Fields[1].AsDateTime := Now;
TBlobField(ADQuery1.Fields[2]).LoadFromFile('C:¥Delphi.exe¥Test.bmp');
Post;
end;
end;
*1 BLOB(Binary Large Object): バイナリデータを格納する場合のデータ型。
キャラクタ型を格納する場合のデータ型をCLOB(Character Large Object) という63

http://www.embarcadero.com/jp

LOB(Large OBject)データの登録／保存 (2/2)
・BLOBデータをファイルへ保存する

BLOBフィールドをTBlobFieldでキャストし、 SaveToFile メソッドでファイルへ出⼒する
procedure TForm1.Button2Click(Sender: TObject);
beginwith ADQuery2 do
begin
Open;
TBlobField(ADQuery2.FieldByName('BlobEntity')).SaveToFile('C:¥Delphi.exe¥Test.bmp');
end;
end;

[実⾏結果]

64

http://www.embarcadero.com/jp

はじめてのFireDAC
TADQueryコンポーネント

65

http://www.embarcadero.com/jp

プロパティの比較
BDE (TQuery)

66

FireDAC (TADQuery)

備考ActiveActiveOpen/Closeメソッドと等価

AutoCalcFields

AutoCalcFields

True:OnCalcFields イベントの発⽣。
計算項⽬の計算を意図的に⽌めたいときはFalseにする

Bof

Bof

True:カーソルがデータセットの先頭にあるCachedUpdates

CachedUpdates

True:キャッシュアップデートが使⽤可能

DatabaseName

ConnectionName

アプリケーション内で参照するときのエリアス名

Eof

Eof

True:カーソルがデータセットの最後にあるIndexFieldNames

IndexFieldNames

テーブルのインデックスフィールドを表⽰

IndexName

IndexName

テーブルの⼆次インデックスをリストから選択

MasterFields

MasterFields

リンクする項⽬をセミコロンで区切って指定

MasterSource

MasterSource

テーブル同⼠をリンクする場合、リンクするテーブルのTDataSourcを指定

ParamsParams

動的SQL⽂のパラメータを指定

ReadOnly

ReadOnly

True:読み取り専⽤
UpdateOptionsオプションに移動

SQL

SQL

SQL⽂を設定

UpdateMode

UpdateMode

更新レコードの検索⽅法をリストから選択
UpdateOptionsオプションに移動

http://www.embarcadero.com/jp

SQL文を設定する
・付属のツールを使⽤すると、SQLの作成と確認を⾏うことができる
・TADQuery コンポーネント上で右クリックし「Query Editor ...」を選択
SQL Commandタブ:

実⾏するSQL⽂を指定｢Execute｣ボタンを押すとSQLを実⾏

Parametersタブ:

SQL⽂にSQLパラメータが指定されている場合、パラメータを指定

Macros タブ:

SQL⽂にマクロパラメータが指定されている場合、パラメータを指定

Optionsタブ:

Format Optionsを指定

67

http://www.embarcadero.com/jp

静的問い合わせSQL⽂を発⾏するメソッドには２種類ある

結果セットを返す場合と、返さない場合とでは使⽤するメソッドが異なる
メソッド

機

能

Open

SELECT⽂を使ってデータセットに問い合わせを⾏い、その結果を受け取る

ExecSQL

INSERT/UPDATE/DELETE⽂などのデータセットに対して操作を⾏い、その結果を返さないSQL⽂を実⾏する// すべてのユーザー⼀覧を返す(Oracle)
procedure TForm1.GetAllUsers(UserList: Tstrings);
begin
UserList.Clear;with ADQuery1 do
begin
try
Close;
Open(‘select distinct username from sys.all_users order by username');while not Eof do
begin
UserList.Add(FieldByName('USERNAME').AsString);
Next;
end;
excepton E: EDatabaseError do
MessageDlg(E.Message, mtError, [mbOK],0);
end;
end;
end;

68

http://www.embarcadero.com/jp

動的問い合わせ
実⾏時にパラメータを指定してSQLを実⾏する

SQL⽂にSQLパラメータ*1 を埋め込むことで、変数のように利⽤できる
プロパティ／メソッド機

能Params[n]変数配列n番⽬に対して値をセットします

ParamByName(Value)

引数Valueに指定された変数名に対して値をセットしますprocedure TForm1.Button1Click(Sender: TObject);
const
strSQL = 'SELECT * FROM EMP WHERE (EMPNO >= :startcode) AND (EMPNO < :endcode)';begin
with ADQuery1 do
begin// SQL⽂をセット
SQL.Clear;
SQL.Add(strSQL);// 変数に値をセットする[次の様に書き換えることもできる]
ParamByName('startcode').AsInteger := 7500;
Params[0].AsInteger := 7500;
ParamByName('endcode').AsInteger := 7900;
Params[1].AsInteger := 7900;// リソースの割り当てと最適化を実⾏する
Prepare;// SQLの実⾏
Open;
end;
end;

*1 SQLパラメータ
バインド変数・ホスト変数とも呼ばれる。パラメータ名の前にコロン(:)を付けて記述します

69

http://www.embarcadero.com/jp

大量のＤＭＬを高速に実行する・FireDACのDML配列機能を使う
・複数のDML(INSERT/UPDATE/DELETE)⽂をパラメータ付きで⼀度に実⾏できる
・⾼速実⾏の実現
通常のExecSQL → 5.5秒
DML配列 → 0.03秒[INSERTの例]
procedure TDataModule1.ExecuteDML;
var
i: Integer;
メモリサイズに注意!
begin// 実⾏するDML(INSERT)SQLをセット
ADQuery1.SQL.Text:= 'INSERT INTO DML_TEST (TINT, TSTRING) VALUES(:f1, :f2)';// 配列の⼤きさをセット
ADQuery1.Params.ArraySize := 1000;// 配列に値をセット
for i:=0 to ADQuery1.Params.ArraySize do
begin
ADQuery1.ParamByName('f1').Values[i-1] := i;
ADQuery1.ParamByName('f2').Values[i-1] := ‘Str' + IntToStr(i);end;// SQLの実⾏
ADQuery1.Execute(ADQuery1.Params.ArraySize, 0);
end;

70

http://www.embarcadero.com/jp

複数SQLのデータセットを利用する
・TADMemTableを使う
・以下のコードは、２つのSQLで得られた結果を複数のTADMemTableに割り付けてセットする
procedure TDataModule1.ExecuteSQL;
begin
ADMemTable1.Close;
ADMemTable2.Close;// SQL実⾏
ADQuery1.SQL.Clear;
ADQuery1.SQL.Add('SELECT * FROM EMP');
ADQuery1.Open;// すべてのレコードを取得
ADQuery1.FetchAll;// ADQuery1のデータをADMemTable1に代⼊ADMemTable1.Data := ADQuery1.Data;// SQL実⾏
ADQuery1.SQL.Clear;
ADQuery1.SQL.Add('SELECT * FROM DEPT');
ADQuery1.Open;// すべてのレコードを取得
ADQuery1.FetchAll;// ADQuery1のデータをADMemTable2に代⼊ADMemTable2.Data := ADQuery1.Data;
DataSource1.DataSet := ADMemTable1;
ADQuery1.Close;
end;

71

http://www.embarcadero.com/jp

データベース例外を捕捉する (1/2)
・BDEでは「EDBEngineError」を捕捉
・FireDACでは「EADDBEngineException」を捕捉

・BDEからの移⾏の場合は、コードの修正が必要
プロパティ

72

説

明

ErrorCodeDBMSのエラーコードを返す

ErrorCount

エラーの総数を⽰す

Errors[n]AnyDAC/DBMSのエラー・警告、またはメッセージのリストを返す

Kind

FireDACで定義されているエラーの種類を返す

Params

実⾏に失敗したパラメータの値を返す

SQL

実⾏に失敗したSQL⽂を返す

http://www.embarcadero.com/jp

データベース例外を捕捉する (2/2)［例外の捕捉例］
procedure TForm1.Button2Click(Sender: TObject);
begin
try
ADQuery1.SQL.Clear;
エラーをキャッチする
ADQuery1.SQL.Add(Memo1.Lines.Text);
ADQuery1.Open();excepton E: EADDBEngineException do
ShowError(E);
end;
end;
procedure TForm1.ShowError(E: EADDBEngineException);var
i: Integer;
begin
Memo2.Lines.Clear;
Memo2.Lines.Add('Message:‘ + E.Message);
Memo2.Lines.Add('ErrorCount:‘ + IntToStr(E.ErrorCount));
for i := 0 to E.ErrorCount - 1 do
begin
Memo2.Lines.Add('ErrorCode:‘ + IntToStr(E.Errors[i].ErrorCode));case E.Kind of
ekUserPwdInvalid: Memo2.Lines.Add(‘ErrorKind： ekUserPwdInvalid');
ekUserPwdExpired: Memo2.Lines.Add(‘ErrorKind： ekUserPwdExpired');ekServerGone: Memo2.Lines.Add(‘ErrorKind： ekServerGone');else
Memo2.Lines.Add(‘ErrorKind： ekOther');
end;
Memo2.Lines.Add('SQL：‘ + E.SQL);
end;
end;

73

http://www.embarcadero.com/jp

マクロを使う
TADQueryのSQL⽂にはマクロパラメータを書くことができる

マクロ機能を使うことにより、RDBMSによって異なるSQL⽅⾔を抽象化すること可能
例えば「⽂字列を⼤⽂字や⼩⽂字に変換する」関数もRDBMSで以下の様に異なる
RDBMS

⼤⽂字に変換

⼩⽂字に変換MS Access

UCASE(⽂字列)

LCASE(⽂字列)MS SQLServer

UPPER(⽂字列)LOWER(⽂字列)

OracleUPPER(⽂字列)LOWER(⽂字列)MySQL

UCASE(⽂字列)

LCASE(⽂字列)PostgreSQLUPPER(⽂字列)LOWER(⽂字列)

マクロを使うと次の様にSQL⽂を書くことができる（Oracle／MySQL）{IF Oracle} SELECT UPPER('ABCabc') FROM DUAL {fi}{IF MYSQL} SELECT UCASE('ABCabc') FROM DUAL {fi}※ 詳しくは FireDAC のヘルプを参照

74

http://www.embarcadero.com/jp

データセットの状態を調べる
TADQueryのStateプロパティを調べるとデータセットの状態を知ることができる
Stateプロパティ

状

態

説

明

dsInactive

⾮アクティブ状態

データセットが開かれていない

dsBrowse

参照状態

データセットは参照モードにある

dsEdit

編集状態

データセットは修正モードにあるdsInsert

挿⼊状態

データセットは挿⼊モードにあるStateプロパティの変化
dsInactive
メソッドの呼出OpendsEdit75

http://www.embarcadero.com/jp

Edit
Post/Cancel

Close

dsBrowse

Append/Insert
Post/Cancel

dsInsert

結果セットの変更
結果セットを変更可能とするか、読み取り専⽤とするかはRequestLiveプロパティで決定される
しかし、複数テーブルの結合や副問い合わせ、集合関数(SUM/AVG)が使われている場合は変更できない
プロパティ
RequestLive

機 能
True:データベースに更新可能な問い合わせの結果セットを要求する

次のSQL⽂を実⾏ (表結合)
SELECT a.EMPNO, a.ENAME, a.JOB, b.DNAMEFROM EMP a, DEPT b
WHERE (a.DEPTNO = b.DEPTNO)

Liveでデータが変更できない･･??

76

http://www.embarcadero.com/jp

はじめてのFireDAC
TADUpdateSQLコンポーネント

77

http://www.embarcadero.com/jp

キャッシュアップデート
・キャッシュアップデートは、データベースへの遅延更新を実現する技術で、ネットワーク負荷の軽減と、読み取り専⽤データセットの更新をサポート
・データセットの更新情報はすべてローカルキャッシュに保存され、メソッドの呼び出しで追加／更新／削除･･をデータベースに反映される

TADQueryでも利⽤可・TADTableの場合は、CachedUpdatesプロパティをTrueにすることでキャッシュアップデートを利⽤することができる
・TADQuery／TADStoredProcの場合は、 TADUpdateSQLコンポーネントを使⽤する
TADQuery
SELECT SQL

メソッドの呼出OpenRDBMSTADUpdateSQL

データセットへの操作

結果セット

UPDATE SQL

更新内容

キャッシュ

78

http://www.embarcadero.com/jp

ApplyUpdates

INSERT SQL
DELETE SQLExecSQL

プロパティの比較
BDE (TUpdateSQL)

FireDAC (TADUpdateSQL)

備－Connection

TADConnectionコンポーネントを指定－

ConnectionName

アプリケーション内で参照するときのエリアス名

DataSet

DataSet *1

TDataSetオブジェクト参照

DeleteSQL

DeleteSQL

結果セットで削除されたレコードをデータセットから削除するSQL⽂を設定

InsertSQL

InsertSQL

結果セットに挿⼊された新規レコードをデータセットにセットするSQL⽂を設定

ModifySQL

ModifySQL

結果セットで値が変更されたレコードをデータセットにセットするSQL⽂を設定*1 DataSetプロパティ：public属性でないため設計時には使⽤できない

79

http://www.embarcadero.com/jp

考キャッシュアップデートの設定 (1/2)
Form(または、データモジュール)にTADQuery(TADTable)、TADUpdateSQLを配置

TADQueryコンポーネントのプロパティを設定
TADQuery80

設定内容

CachedUpdatesTrueに設定。

UpdateObject

TADUpdateSQLコンポーネントを指定

http://www.embarcadero.com/jp

キャッシュアップデートの設定 (2/2)
更新⽤のSQL⽂を「Update SQL Editor」で設定する

・TADUpdateSQLコンポーネントを選択し、オブジェクトインスペクタの下にある｢Update SQL Editor ...｣をクリックする※SQL⽂は「更新する表単位」に必要※項⽬を変更した場合は、｢Generate SQL｣ボタンを必ず押して下さい

Generateタブ:

更新対象のテーブル名、キー項⽬、更新する項⽬を設定

Optionタブ:⽣成するSQL⽂の種類、形式等を設定

SQL Commandsタブ:

⽣成されたSQL⽂を確認することができる※データセットが閉じていると次の警告が出る

81

http://www.embarcadero.com/jp

更新情報のサーバーへの書き込み
サーバーへの書き込みは、ApplyUpdatesメソッドを呼び出す
メソッド

機

能

ApplyUpdates

キャッシュの更新情報をデータベースサーバーに書き込む

CancelUpdates

キャッシュに保留している更新をすべてクリアする

CommitUpdates

ローカルキャッシュの内容をクリアする

procedure TDataModule1.ExecutUpdate;begin// トランザクションの開始
if not ADConnection1.InTransaction then ADConnection1.StartTransaction;try// 変更をデータベースサーバーに書き込む
if ADQuery1.UpdatesPending then ADQuery1.ApplyUpdates;// トランザクションのコミット
ADConnection1.Commit;
except// トランザクションのロールバック
ADConnection1.Rollback;raise;
end;// キャッシュアップデートバッファのクリア
ADQuery1.CommitUpdates;
ADQuery1.Refresh;
end;

82

http://www.embarcadero.com/jp

OnUpdateRecord イベント・キャッシュアップデートによる更新は、⾃動的に更新SQLを⽣成し実⾏される※OnUpdateRecordイベントが割り当てられていると更新は⾏われません！
・逆な⾔い⽅をすれば、複雑な更新制御を施すことができる
・下のコードは、OnUpdateRecordイベントが割り当てられていない場合と等価
procedure TDataModule1.ADQuery1UpdateRecord(ASender: TDataSet;
ARequest: TADUpdateRequest; var AAction: TADErrorAction;
AOptions: TADUpdateRowOptions);
begin
ADUpdateSQL1.Apply(ARequest, AAction, AOptions);
AAction := eaApplied;
end;
クラス

83

内 容

TADUpdateRequest

arInsert, arUpdate, arDelete, arLock, arUnlock, arFetchRow, arUpdateHBlobs,
arDeleteAll, arFetchGenerators

TADErrorAction

eaFail, eaSkip, eaRetry, eaApplied, eaDefault, eaExitSuccess, eaExitFailure

TADUpdateRowOption

uoCancelUnlock, uoImmediateUpd, uoDeferredLock, uoOneMomLock,
uoNoSrvRecord, uoDeferredGenGet

http://www.embarcadero.com/jp

OnUpdateError イベント
・次のコードでは、アプリケーション例外が実⾏される（サイレント例外）・exceptの例外処理は実⾏されない
procedure TDataModule1.ExecutUpdate;
begin
try
ADQuery1.ApplyUpdates;
ADQuery1.CommitUpdates;
except// 例外処理を記述
raise;
例外が発⽣しない･･!?
end;
end;

・キャッシュアップデートの例外処理は OnUpdateErrorイベントに記述する
procedure TDataModule1.ADQuery1UpdateError(ASender: TDataSet;
AException: EADException; ARow: TADDatSRow; ARequest: TADUpdateRequest;
var AAction: TADErrorAction);
begin
ADConnection1.Rollback;
end;

84

http://www.embarcadero.com/jp

はじめてのFireDAC
TADStoredProcコンポーネント

85

http://www.embarcadero.com/jp

プロパティの比較
FireDACでは、プロパティ・イベント・メソッドが⼤幅に追加されている
BDE (TStoredProc)

FireDAC (TADStoredProc)

備

考

－

Connection

TADConnectionコンポーネントを指定

DatabaseName

ConnectionName

アプリケーション内で参照するときのエリアス名

ExecProc

ExecProc

ストアドプロシージャの実⾏－

PackageName

パッケージ名を指定

ParamsParamsパラメータの名前、値、およびデータ型を設定

ParamBindMode

ParamBindMode *1

パラメータをストアドプロシージャの変数名か、変数順
番かを指定

PreparePrepareストアドプロシージャをメモリーにロード※記述位置に注意

SchemaName

SchemaName

スキーマ名を指定

StoredProcName

StoredProcName

ストアドプロシージャ名を指定[*1 ParamBindModeプロパティ]

86

値

順序

pbByName

パラメータをストアドプロシージャの変数名で指定（デフォルト値）

pbByNumber

パラメータをストアドプロシージャの変数順番で指定

http://www.embarcadero.com/jp

PROCEDUREの実行 (1/4)
・以下のSQL⽂を実⾏し、Oracleサーバーにプロシジャ ｢ProcA｣ を登録する
CREATE OR REPLACE PROCEDURE ProcA (i1 IN NUMBER,
i2 IN NUMBER,
o1 OUT NUMBER) AS
BEGIN
o1 := i1 + i2;
RETURN;
END;

・データモジュールにコンポーネントを配置

87

http://www.embarcadero.com/jp

PROCEDUREの実行 (2/4)
・ConnectionName(またはConnection)プロパティを設定し、TADConnectionコンポーネントと結び付ける
・データモジュールに、次のコードを記述（呼ばれる側）
procedure TDataModule1.ExcProcA(const i1, i2: Integer; var o1: Integer);
begin
with ADStoredProc1 do
begin// プロシジャ名の設定[次の様に書き換えることもできる]
StoredProcName := 'ProcA';
with ADStoredProc1 do// プロシジャの読み込み
begin
Prepare;StoredProcName := 'ProcA';// パラメータの設定
Prepare;Params[0].AsInteger := i1;
ParamByName('i1').AsInteger := i1;
Params[1].AsInteger := i2;
ParamByName('i2').AsInteger := i2;
ExecProc;// プロシジャの実⾏
o1 := Params[2].AsInteger;
ExecProc;end;// 実⾏結果の受け取り
o1 := ParamByName('o1').AsInteger;
end;
end;

88

http://www.embarcadero.com/jp

PROCEDUREの実行 (3/4)
・以下のコードを記述（呼出側）
procedure TForm1.Button2Click(Sender: TObject);var
o1: Integer;
begin
DataModule1.ExcProcA(1000, 250, o1);
Edit1.Text := IntToStr(o1);end;・実⾏エラーが発⽣ !?

89

http://www.embarcadero.com/jp

PROCEDUREの実行 (4/4)
・エラー回避策として次の2通りがある(1). Valueパラメータ(バリアント型)を使⽤する
procedure TDataModule1.ExcProcA(const i1, i2: Integer; var o1: Integer);
begin
with ADStoredProc1 do
begin
StoredProcName := 'ProcA';
Prepare;ParamByName('i1').Value := i1;
ParamByName('i2').Value := i2;
ExecProc;
o1 := ParamByName('o1').Value;
end;
end;

(2).データ型のマッピング・ルールを指定する
・Connection Editor の｢Options｣で設定する
・この例では、｢dtFmtBCD｣を｢dtInt32｣にマッピングする

90

http://www.embarcadero.com/jp

FUNCTIONの実行 (1/3)
・以下のSQL⽂を実⾏し、Oracleサーバーにプロシジャ ｢FuncA｣ を登録する
CREATE OR REPLACE FUNCTION FuncA (i1 IN NUMBER,
i2 IN NUMBER) RETURN NUMBER AS
BEGIN
RETURN i1 + i2;
END;

・データモジュールにコンポーネントを配置

91

http://www.embarcadero.com/jp

FUNCTIONの実行 (2/3)
・ConnectionName(またはConnection)プロパティを設定し、TADConnectionコンポーネントと結び付ける
・データモジュールに、次のコードを記述（呼ばれる側）
function TDataModule1.ExcFuncA(const i1, i2: Integer): Integer;
begin
with ADStoredProc1 do
begin// ファンクション名の設定
StoredProcName := 'FuncA';// ファンクションの読み込み
Prepare;// パラメータの設定
ParamByName('i1').Value := i1;
ParamByName('i2').Value := i2;// ファンクションの実⾏
ExecProc;// 出⼒パラメータを返す
Result := ParamByName('RESULT').Value;
end;
end;

92

http://www.embarcadero.com/jp

FUNCTIONの実行 (3/3)
・以下のコードを記述（呼出側）
procedure TForm1.Button3Click(Sender: TObject);var
o1: Integer;
begin
o1 := DataModule1.ExcFuncA(1000, 250);
Edit2.Text := IntToStr(o1);end;[実⾏結果]

93

http://www.embarcadero.com/jp

PACKAGEの実行 (1/5)
・パッケージはORACLE固有のデータベースオブジェクト
・PROCEDUREやFUNCTION を１つにまとめることが可能
・パッケージは仕様部と本体部の２つのオブジェクトから構成

コンパイル時に使⽤

仕様部（引数、戻り値）プログラム

実⾏時に使⽤

本体部（実装は隠蔽）94

http://www.embarcadero.com/jp

PACKAGEの実行 (2/5)
・以下のSQL⽂を実⾏し、Oracleサーバーにプロシジャ ｢ PackA ｣ を登録する/* 仕様部 */CREATE OR REPLACE PACKAGE PackA AS
PROCEDURE ProcA(i1 IN NUMBER, i2 IN NUMBER, o1 OUT NUMBER);FUNCTION FuncA(i1 IN NUMBER, i2 IN NUMBER) RETURN NUMBER;
END PackA;//* 本体部 */CREATE OR REPLACE PACKAGE BODY PACKA AS
PROCEDURE ProcA (i1 IN NUMBER,
i2 IN NUMBER,
o1 OUT NUMBER) IS
BEGIN
o1 := i1 + i2;
RETURN;END;
FUNCTION FuncA (i1 IN NUMBER,
i2 IN NUMBER) RETURN NUMBER IS
BEGIN
RETURN i1 + i2;
END;
END PackA;95

http://www.embarcadero.com/jp

PACKAGEの実行 (3/5)
・データモジュールにコンポーネントを配置

・ConnectionName(またはConnection)プロパティを設定し、TADConnectionコンポーネントと結び付ける
・データモジュールに次のコードを記述
procedure TDataModule1.DataModuleCreate(Sender: TObject);
begin
ADConnection1.Connected := True;
ADStoredProc1.PackageName := 'PackA';
end;

96

http://www.embarcadero.com/jp

PACKAGEの実行 (4/5)
・データモジュールに、ProcA、FuncAを実⾏するコードを記述[ProcA]

procedure TDataModule1.ExcProcA(const i1, i2: Integer; var o1: Integer);
begin
with ADStoredProc1 do
begin
StoredProcName := 'ProcA';
Prepare;ParamByName('i1').Value := i1;
ParamByName('i2').Value := i2;
ExecProc;
o1 := Params[2].Value;
end;
end;

[FuncA]
function TDataModule1.ExcFuncA(const i1, i2: Integer): Integer;
begin
with ADStoredProc1 do
begin
StoredProcName := 'FuncA';
Prepare;ParamByName('i1').Value := i1;
ParamByName('i2').Value := i2;
ExecProc;
Result := ParamByName('RESULT').Value;
end;
end;

97

http://www.embarcadero.com/jp

PACKAGEの実行 (5/5)
・以下のコードを記述（呼出側）
procedure TForm1.Button2Click(Sender: TObject);var
o1: Integer;
begincase ComboBox1.ItemIndex of
0: // FuncA
o1 := DataModule1.ExcFuncA(StrToInt(Edit1.Text), StrToInt(Edit2.Text));
1: // ProcA
DataModule1.ExcProcA(StrToInt(Edit1.Text), StrToInt(Edit2.Text), o1);
end;
Edit3.Text := IntToStr(o1);end;[実⾏結果]

98

http://www.embarcadero.com/jp

はじめてのFireDAC
まとめ99

http://www.embarcadero.com/jp

まとめ・BDEとの⾼い互換性により、移⾏⼯数を最低限に抑えることが可能
・いろいろなデータベースへの接続を可能とするコンポーネント群
・ハイパフォーマンス
・エンタープライズデータベースに簡単に接続することが可能
・統⼀的なデータアクセスの提供と、⾼度なマクロ機能によりデータベース固有の処理も可能
・最新のOS・DBMSバージョンに対応
・約60個を超える豊富なオプション

100

http://www.embarcadero.com/jp

参考情報
FireDAC ヘルプ

http://docs.embarcadero.com/products/rad_studio/firedac/frames.html?frmname=topic&frmfile=index.html

RAD Studioマイグレーションセンター

http://www.embarcadero.com/jp/rad-in-action/migration-upgrade-center

FireDAC Q&A

http://www.embarcadero.com/jp/products/rad-studio/firedac-faq

BDE から FireDAC への移⾏ - Paradox から InterBase の場合
http://edn.embarcadero.com/jp/article/42974

AnyDACのデモ (Dmitry Arefiev)

http://www.youtube.com/watch?v=vCM-PcZFdWA

101

http://www.embarcadero.com/jp

ご清聴
ありがとうございました「 Delphi talks 」メンバー募集中！
Facebookを利⽤して、Delphiのこと、C++Builderこと、いろいろなことを語り合いませんか?
時々、勉強会やオフ会もやっています。皆さまの参加をお待ちしています。
https://www.facebook.com/groups/delphitalks/102

http://www.embarcadero.com/jp102