Migaro. 技術Tips

                       

ミガロ. 製品の技術情報
IBMiの活用に役立つ情報を掲載!


【Delphi/400】TClientDataSetでApplyUpdatesを行う前に

TClientDataSetコンポーネントはデータをキャッシュ上に取り込むため、
アクセスが早くまたインデックスを自由に追加・変更できるなどの機能があり便利です。

10 Seattle以降の新しいバージョンではFireDAC接続の利用が主流になり、
TFDMemTableを利用する機会が多くなっていますが、TClientDataSetも利用可能です。
(TFDMemTableでの同様の更新処理については、次回のTipsで紹介します。)

TClientDataSetのデータを変更したときにはキャッシュ上のみの一時変更のため、
それをDBに反映させる場合は別途処理を行う必要があります。
一般的にはApplyUpdatesメソッドの呼び出しで反映できます。
(内部的には、Deltaというデータ域に保持されている一時変更を内部生成されるSQLで更新します。)

ただし複数の更新を一括で行うという機能上、トランザクション処理が推奨になります。
(途中でエラーになった時にロールバックできる方が安全です。)

procedure TForm1.Button4Click(Sender: TObject);
var
  iErrors: Integer;
begin
  if ClientDataSet1.ChangeCount = 0 then
  begin
    ShowMessage('適用する変更がありません。');
    Exit;
  end;

  (**【ここでトランザクション開始】※接続方式により記述方法が異なる**)
  try
    iErrors := ClientDataSet1.ApplyUpdates(-1);
    if iErrors = 0 then
    begin
      (**【ここでコミット】※接続方式により記述方法が異なる**)
      ShowMessage('変更を反映しました。');
    end
    else
    begin
      (**【ここでロールバック】※接続方式により記述方法が異なる**)
      ShowMessage(IntToStr(iErrors) + '件の変更を適用できませんでした。');
    end;
  except
    on E: Exception do
    begin
      (**【ここでロールバック】※接続方式により記述方法が異なる**)
      raise; // 元々の例外処理
    end;
  end;
end;

 

上記のサンプルロジックのようにトランザクションを使った更新をする場合は、
次の2点の準備が必要になります。
 

1. IBM i 上で対象ファイルのジャーナルが開始されていること

IBM i はトランザクション処理をジャーナル機能を使って実現しています。
そのため、ジャーナルが開始状態になっていないとトランザクション処理を行うことはできません。
(他DBの場合でも、ファイル側のトランザクションが有効になっている必要があります。)
 

2. トランザクションレベルで *NONE 以外の値が設定されていること

IBM i のデータベース接続時のトランザクションレベルに設定できる値は
*NONE、*CHG、*CS、*ALL
の4種類で、IBM i 上でコミットメント制御と呼ばれるものと同じです。

どのパラメータを指定すれば良いのかは更新内容やシステムの要件によりますが、
オンライン系の画面処理(対話形式)であれば、読み取りロックのかからない
「*CHG」を選択するケースが一般的です。

 

以下、それぞれの接続方式について、Delphi/400で接続する際の
パラメータ設定および開始/コミット/ロールバック時のロジック例を紹介します。

 

FireDAC接続(ドライバCO400)

Delphi/400 10 Seattle以降で利用可能なFireDAC接続においては、
TFDConnection内の [ODBCAdvanced] パラメータで、
下記例のようにCommitmentという設定値を定義してから接続します。

このパラメータではLibraryOptionでデフォルトライブラリの指定も行っていますが、
セミコロンで区切ることで両方の設定を保持できます。
(いずれも、設定しない場合は省略可)

//(記述例1)
FDConnection1.Params.Values['ODBCAdvanced'] := 'Commitment=*CHG';
//(記述例2)※LibraryOptionなど他パラメータと併用の場合
FDConnection1.Params.Values['ODBCAdvanced'] := 'LibraryOption=TESTLIB;Commitment=*CHG';
トランザクションレベルCommitment 設定値
*CHGCommitment=*CHG
*CSCommitment=*CS
*ALLCommitment=*ALL
*NONE記述しない

 
TFDMemTableを利用する場合はApplyUpdatesメソッドだけでは更新できませんので、
詳細な手順を次回のTipsで解説します。
ただしトランザクションレベルの設定は上記の通りです。

// トランザクション記述の例
begin
  FDConnection1.StartTransaction; // トランザクション開始
  try
    // ここで各種更新処理(ApplyUpdatesの場合もここ)

    if FDConnection1.InTransaction then
      FDConnection1.Commit; // コミット
  except
    if FDConnection1.InTransaction then
      FDConnection1.Rollback; // ロールバック
    raise; // 元々の例外処理
  end;
end;

 

dbExpress接続(ドライバCO400)

Delphi/400 V2007以降のバージョンでは、
TSQLConnection内の [BLOBSIZE] パラメータで設定値を定義してから接続します。

//(記述例)
SQLConnection1.Params.Values['BlobSize'] := '-2';
トランザクションレベルBlobSize 設定値
*CHG-2
*CS-3
*ALL-4
*NONE-1 および上記以外の値
// トランザクション記述の例
// (変数使用のため、uses節に『Data.DBXCommon』を追加)
var
  dbTranUp: TDBXTransaction; // トランザクション情報保持変数(更新用)
begin
  dbTranUp := SQLConnection1.BeginTransaction; // トランザクション開始
  try
    // ここで各種更新処理(ApplyUpdatesの場合もここ)

    if SQLConnection1.InTransaction then
      SQLConnection1.CommitFreeAndNil(dbTranUp); // コミット
  except
    if SQLConnection1.InTransaction then
      SQLConnection1.RollbackFreeAndNil(dbTranUp); // ロールバック
    raise; // 元々の例外処理
  end;
end;

 

BDE接続(ドライバIDCO400)

エリアスをご利用いただいている場合は、BDE Administratorで該当する
エリアスの [TRAN_ISOLATION] パラメータを設定してから接続します。
TDatabaseの接続時にパラメータを指定している場合は、そこで指定します。

なおBDE接続では、トランザクション制御が必須となります。
(不使用の場合「現在進行中のユーザートランザクションはありません.」エラー)

//(記述例)
Database1.Params.Values['TRAN_ISOLATION'] := '*CHG';
トランザクションレベルTRAN_ISOLATION 設定値
*CHG*CHG
*CS*CS
*ALL*ALL
*NONE*NONE および上記以外の値
// トランザクション記述の例
begin
  Database1.StartTransaction; // トランザクション開始
  try
    // ここで各種更新処理(ApplyUpdatesの場合もここ)

    if Database1.InTransaction then
      Database1.Commit; // コミット
  except
    if Database1.InTransaction then
      Database1.Rollback; // ロールバック
    raise; // 元々の例外処理
  end;
end;

 

その他の留意点

  • いずれの接続方式においても、内部的には更新SQLが生成・実行されています。
    そのため参照元のファイルがUNIQUEでない場合、全てのフィールドの値が全く同じレコードが
    複数ある状態では、そのレコードを更新(UPDATE/DELETE)することはできません。
    (複数行が更新対象になるため、「更新作業は複数のレコードに影響を与えました。」などのエラー)
  • BDE接続時は、アプリケーションを管理者として実行していないと、更新エラーの原因となります。
  • dbExpress接続時は、V2006以前のバージョンではトランザクション設定の記述方法が異なります。
  • ApplyUpdates時に「パラメータが無効です。」エラーが出る場合は、
    TClientDataSet使用時に必要なMidaslibのバージョンが一致していない可能性があります。
    プロジェクトファイル(~~.dpr)のuses節に「MidasLib」が存在するかご確認ください。

 

<関連リンク>※Embarcadero Docwiki

 

 

(ミガロ.情報マガジン「MIGARO News!!」Vol.116 2010年7月号より、FireDAC部分を加筆)