德尔福&共享数据源

时间:2009-06-11 17:29:22

标签: delphi datasource

在我的应用程序中,我有不同的表单使用相同的数据源(因此查询也是相同的),在公共数据模块中定义。问题是,有没有办法知道我打开一个特定的查询多少次?通过能够做到这一点,我可以避免关闭该查询而不关闭它“其他地方”。

编辑:重要的是要提到我使用的是Delphi3,它不是单个查询而是几个。

4 个答案:

答案 0 :(得分:5)

我们的想法是使用TDataSource的 DataLinks 属性 但是,由于它受到保护,您必须获得访问权限。一个常见的技巧是创建一个假的后代只是为了铸造:

type
  TDataSourceHack = class(TDataSource);

然后你就像使用它一样:

  IsUsed := TDataSourceHack(DataSource1).DataLinks.Count > 0;

答案 1 :(得分: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适用于此。您需要对TDataset后代进行适当的更改,如果您使用的是旧版本的Delphi,还需要创建一个FreeAndNil函数。我用于此的概念是维护您请求的所有查询的列表,并通过句柄操作它们,该句柄实际上是列表中查询的索引。 FreeUnusedQueries方法可以释放任何不再有引用的对象......这也可以作为close查询方法的一部分来完成,但是我把它分开来处理需要另一个特定查询重新打开的情况。模块。

  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;

答案 2 :(得分: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;

然后只需在数据模块中包含该单元,并更改对共享数据集的引用(如果使用的是组件,则还必须注册此项并将其添加到调色板中)。完成此操作后,您不必对其他单元进行更改,因为数据集仍然是原始单元的后代。使这一切工作的原因是创建了被覆盖的对象。

答案 3 :(得分:0)

您可以在共享数据模块上使用通用TDataSet,并使用Field参数的DataSet属性将其设置在OnDataChange上

  

dstDataSet:= Field.DataSet;

这样,当你想要关闭数据集时,关闭数据模块上的数据集,这是一个指向你甚至不需要知道的某种形式的正确数据集的指针

相关问题