2

私のアプリでは、共通のデータモジュールで定義された、同じデータソースを使用するさまざまなフォームがあります (したがって、クエリも同じです)。質問は、特定のクエリを何回開いたかを知る方法はありますか? これができることで、「どこでも」閉じずにそのクエリを閉じることを避けることができました。

編集:私は Delphi3 を使用していることに言及することが重要であり、それは単一のクエリではなく複数です。

4

4 に答える 4

5

アイデアは、TDataSource のDataLinksプロパティを使用することです。
ただし、保護されているため、アクセスする必要があります。一般的なトリックの 1 つは、キャストの目的だけで偽の子孫を作成することです。

type
  TDataSourceHack = class(TDataSource);

次に、次のように使用します。

  IsUsed := TDataSourceHack(DataSource1).DataLinks.Count > 0;
于 2009-06-11T21:58:11.057 に答える
3

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;
于 2009-06-11T18:21:45.790 に答える
1

わかりました、まったく異なる解決策です... 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;

次に、データ モジュールにユニットを含め、共有データセットへの参照を変更します (コンポーネントを使用している場合は、これを登録してパレットに追加する必要もあります)。これが完了したら、データセットは元のデータセットの子孫であるため、他のユニットを変更する必要はありません。これをすべて機能させるのは、オーバーライドされたオブジェクトの作成です。

于 2009-06-17T15:45:03.787 に答える
0

Field パラメータの DataSet プロパティを使用して、共有データモジュールに汎用の TDataSet を設定し、OnDataChange に設定することができます。

dstDataSet:= Field.DataSet;

このようにして、データセットを閉じたい場合は、データモジュールのデータセットを閉じます。これは、知る必要のないフォームの正しい DataSet へのポインターです。

于 2009-06-11T18:04:38.933 に答える