私のアプリでは、共通のデータモジュールで定義された、同じデータソースを使用するさまざまなフォームがあります (したがって、クエリも同じです)。質問は、特定のクエリを何回開いたかを知る方法はありますか? これができることで、「どこでも」閉じずにそのクエリを閉じることを避けることができました。
編集:私は Delphi3 を使用していることに言及することが重要であり、それは単一のクエリではなく複数です。
私のアプリでは、共通のデータモジュールで定義された、同じデータソースを使用するさまざまなフォームがあります (したがって、クエリも同じです)。質問は、特定のクエリを何回開いたかを知る方法はありますか? これができることで、「どこでも」閉じずにそのクエリを閉じることを避けることができました。
編集:私は Delphi3 を使用していることに言及することが重要であり、それは単一のクエリではなく複数です。
アイデアは、TDataSource のDataLinksプロパティを使用することです。
ただし、保護されているため、アクセスする必要があります。一般的なトリックの 1 つは、キャストの目的だけで偽の子孫を作成することです。
type
TDataSourceHack = class(TDataSource);
次に、次のように使用します。
IsUsed := TDataSourceHack(DataSource1).DataLinks.Count > 0;
addref/release のようなアプローチを使用して創造的になることができます。共有データモジュールにいくつかの関数と整数変数を作成して魔法を実行し、必ずそれらを呼び出してください..部分的なコードは次のとおりです。
TDMShared = class(tDataModule)
private
fQueryCount : integer; // set to 0 in constructor
public
function GetQuery : tDataset;
procedure CloseQuery;
end;
function TDMShared.GetQuery : tDataset;
begin
inc(fQueryCount);
if fQueryCount = 1 then
SharedDatsetQry.open;
Result := shareddatasetqry; // your shared dataset here
end;
procedure TDMShared.CloseQuery;
begin
dec(fQueryCount);
if fQueryCount <= 0 then
shareddatasetqry.close; // close only when no refs left.
end;
編集:複数のクエリでこれを行うには、クエリ参照を保持するコンテナーと、それらを操作する方法が必要です。これには tList が適しています。古いバージョンの Delphi を使用している場合は、TDataset の子孫に適切な変更を加え、FreeAndNil 関数を作成する必要があります。私がこれに使用した概念は、要求したすべてのクエリのリストを維持し、実際にはリスト内のクエリのインデックスであるハンドルによってそれらを操作することでした。メソッド FreeUnusedQueries は、参照を持たなくなったオブジェクトを解放するためにあります...これは、クエリを閉じるメソッドの一部としても実行できますが、特定のクエリを別のクエリで再度開く必要がある場合を処理するために分離しましたモジュール。
Procedure TDMShared.DataModuleCreate(Sender:tObject);
begin
dsList := tList.create;
end;
Function TDMShared.CreateQuery(aSql:String):integer;
var
ds : tAdoDataset;
begin
// create your dataset here, for this example using TADODataset
ds := tAdoDataset.create(nil); // self managed
ds.connection := database;
ds.commandtext := aSql;
ds.tag := 0;
Result := dsList.add(ds);
end;
function TDMShared.GetQuery( handle : integer ) : tDataset;
begin
result := nil;
if handle > dsList.count-1 then exit;
if dsList.Items[ handle ] = nil then exit; // handle already closed
result := tAdoDataset( dsList.items[ handle ]);
Inc(Result.tag);
if Result.Tag = 1 then
Result.Open;
end;
procedure TDMShared.CloseQuery( handle : integer );
var
ds : tAdoDataset;
begin
if handle > dsLIst.count-1 then exit;
ds := tAdoDataset( dsList.items[ handle ]);
dec(ds.Tag);
if ds.Tag <= 0 then
ds.close;
end;
procedure TDMShared.FreeUnusedQueries;
var
ds : tAdoDataset;
ix : integer;
begin
for ix := 0 to dsList.Count - 1 do
begin
ds := tAdoDataset(dsLIst.Items[ ix ]);
if ds.tag <= 0 then
FreeAndNil(dsList.Items[ix]);
end;
end;
procedure TDMShared.DataModuleDestroy(Sender: TObject);
var
ix : integer;
begin
for ix := 0 to dsList.count-1 do
begin
if dsLIst.Items[ix] <> nil then
FreeAndNil(dsLIst.Items[ix]);
end;
dsList.free;
end;
わかりました、まったく異なる解決策です... Delphi 3で機能するはずです。
既存のデータセットから新しいユニットに新しい「子孫オブジェクト」を作成し、新しいオブジェクトにいくつかの動作を追加します。残念ながら、テスト用の Delphi 3 はありませんが、適切なアクセス ポイントが見つかれば動作するはずです。例えば:
TMySharedDataset = class(tOriginalDataset)
private
fOpenCount : integer;
protected
procedure Internal_Open; override;
procedure Internal_Close; override;
end;
TMySharedDataset.Internal_Open;
begin
inherited Internal_Open;
inc(fOpenCount);
end;
TMySharedDataset.Internal_Close;
begin
dec(fOpenCount);
if fOpenCount <= 0 then
Inherited Internal_Close;
end;
次に、データ モジュールにユニットを含め、共有データセットへの参照を変更します (コンポーネントを使用している場合は、これを登録してパレットに追加する必要もあります)。これが完了したら、データセットは元のデータセットの子孫であるため、他のユニットを変更する必要はありません。これをすべて機能させるのは、オーバーライドされたオブジェクトの作成です。
Field パラメータの DataSet プロパティを使用して、共有データモジュールに汎用の TDataSet を設定し、OnDataChange に設定することができます。
dstDataSet:= Field.DataSet;
このようにして、データセットを閉じたい場合は、データモジュールのデータセットを閉じます。これは、知る必要のないフォームの正しい DataSet へのポインターです。