お世話になります。
Delphi2007、Windows7、Oracle11g環境で
TADOConnection→TADOTable と
TSQLConnection→TSQLTable→TDataSetProvider→TClientDataSet を
利用してMS-AccessのテーブルをOracleにコピーするプログラムを作成しています。
下記のプログラムを実行してこれまでは問題なかったのですが、この度フィールド数および
レコード数がとても多いテーブルをコピーすることになり、同じように実行したところ、
コピー中に「メモリが足りません」と出るようになりました
下記仕様だとApplyUpdatesが実行されるまでメモリを使い続けると思い、
Self.adoTable.Next; の下の行に10000レコードPostするたびに
ApplyUpdatesを実行してみたのですが、これでは改善されませんでした。
ApplyUpdatesを実行しただけではRecordは消えていないため、
メモリが無くなるかと思い、ApplyUpdatesの後にclientDataSetのClose→Openを
追加したらきちんと動きましたが、これが本当に正しい対処かどうか自分には
判断つきませんでした。有識者の方はどのような対処が妥当であるか教えて頂けませんか。
Self.sqlTable.Open;
Self.clientDataSet.Open;
// 全レコード削除
Self.sqlTable.DeleteRecords;
Self.adoTable.Open;
Self.adoTable.First;
// Accessのテーブルから1レコードずつ取得
while not Self.adoTable.Eof do
begin
Self.clientDataSet.Append;
// 全フィールドのValueをコピー
for intCount := 0 to arySFields.Count - 1 do
begin
Self.clientDataSet.FieldByName(arySFields.Strings[intCount]).Value :=
Self.adoTable.FieldByName(aryDFields.Strings[intCount]).Value;
// ★★★★★ ここに仕掛けを追加してみた
end;
Self.clientDataSet.Post;
Self.adoTable.Next;
end;
Self.clientDataSet.ApplyUpdates(-1);
arySFields.Free;
aryDFields.Free;
Self.clientDataSet.Close;
Self.adoTable.Close;
Self.sqlTable.Close;
Self.adoConnection.Close;
Self.sqlConnection.Close;
間違えていました。仕掛けを追加したのは↓です。
また、sqlTableはTSQLTable、adoTableはTADOTable、
clientDataSetはTClientDataSetです
while not Self.adoTable.Eof do
begin
Self.clientDataSet.Append;
// 全フィールドのValueをコピー
for intCount := 0 to arySFields.Count - 1 do
begin
Self.clientDataSet.FieldByName(arySFields.Strings[intCount]).Value :=
Self.adoTable.FieldByName(aryDFields.Strings[intCount]).Value;
end;
Self.clientDataSet.Post;
Self.adoTable.Next;
// ★★★★★ ここに仕掛けを追加してみた
end;
TClientDataSetはDataControlへ接続するものですね。直にTSQLTableのFieldへ代入するのはダメでしょうか?その場合、TSQLConnectionのトランザクションを利用します。
かなり単純になります。
お世話になります。
dbExpressのTSQLTableのValueにはコピーできないものと
思い込んでいました。明日早速試してみます。
ご意見ありがとうございました。
教えて頂いたような変更を行ってみたのですが、下記コードを実行すると
Append実行時に「書込み禁止のデータを変更できません」と表示されます。
TSQLTableのプロパティで注意すべき点とか御座いますか?
dbxTrans:= Self.sqlConnection.BeginTransaction;
・・・・中略・・・・
Self.sqlTable.Open;
// 全レコード削除
Self.sqlTable.DeleteRecords;
Self.adoTable.Open;
Self.adoTable.First;
// Accessのテーブルから1レコードずつ取得
while not Self.adoTable.Eof do
begin
Self.sqlTable.Append;
for intCount := 0 to arySFields.Count - 1 do
begin
Self.sqlTable.FieldByName(arySFields.Strings[intCount]).Value :=
Self.adoTable.FieldByName(aryDFields.Strings[intCount]).Value;
end;
Self.sqlTable.Post;
Self.adoTable.Next;
end;
Self.sqlConnection.CommitFreeAndNil(dbxTrans);
arySFields.Free;
aryDFields.Free;
Self.adoTable.Close;
Self.sqlTable.Close;
Tableをあまり使ったことがないのです。
どうも、AppendでDataSetをNullで更新するようです。
OnNewRecordイベントでキーを設定するのではいかがでしょうか?
Tableではバックグラウンドで SQL 文を使っています。
早いうちにADOQueryを使ったほうがいいのではないでしょうか?
ADOQueryのInsert文を使えば問題ありません。
OracleがUpdate or Inset文をサポートしていれば便利です。
お世話になります。
ご指摘頂いたようにTADOQueryやTSQLQueryを使えば動作することは
理解しているのですが、テーブルの型なども様々であり、コードが複雑に
なると実装時に判断して現状の仕様となりました。
ただ暫定対処はどうしても納得いかなかったので、
TSQLConnection→TSQLTable→TDataSetProvider→TClientDataSet を
TADConnection→TADTable に置き換える対応を行いました。
この対応でメモリエラーはおきなくなりました。
参考になるご意見色々ありがとうございました。
ツイート | ![]() |