Delphi и общие источники данных - PullRequest
2 голосов
/ 11 июня 2009

В моем приложении есть разные формы, использующие один и тот же источник данных (поэтому запросы тоже одинаковые), определенные в общем модуле данных. Вопрос в том, есть ли способ узнать, сколько раз я открывал конкретный запрос? Будучи способным сделать это, я мог избежать закрытия этого запроса, не закрывая его «везде, где еще».

Изменить: Важно отметить, что я использую Delphi3, и это не один запрос, а несколько.

Ответы [ 4 ]

5 голосов
/ 12 июня 2009

Идея состоит в том, чтобы использовать свойство DataLinks TDataSource.
Но, поскольку он защищен, вы должны получить к нему доступ. Один из распространенных приемов - создать поддельного потомка только для приведения:

type
  TDataSourceHack = class(TDataSource);

Тогда вы используете это как:

  IsUsed := TDataSourceHack(DataSource1).DataLinks.Count > 0;
3 голосов
/ 11 июня 2009

Вы можете проявить творческий подход, используя подход типа 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, а также создать функцию FreeAndNil, если вы используете более старую версию Delphi. Концепция, которую я использовал для этого, состояла в том, чтобы поддерживать список всех запрашиваемых вами запросов и манипулировать ими с помощью дескриптора, который фактически является индексом запроса в списке. Метод 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;
1 голос
/ 17 июня 2009

Хорошо, это совершенно другое решение ... которое должно работать для 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;

Затем просто включите модуль в свой модуль данных и измените ссылку на ваш общий набор данных (вам также придется зарегистрировать этот и добавить его в палитру, если вы используете компоненты). Как только это будет сделано, вам не придется вносить изменения в другие юниты, так как набор данных все еще является потомком вашего исходного. То, что заставляет все это работать, - это создание ВАШЕГО переопределенного объекта.

0 голосов
/ 11 июня 2009

Вы можете иметь общий TDataSet в общем модуле данных и установить его в OnDataChange, используя свойство DataSet параметра Field

dstDataSet: = Field.DataSet;

Таким образом, когда вы хотите закрыть набор данных, закройте набор данных в модуле данных, который является указателем на правильный набор данных в какой-либо форме, которую вам даже не нужно знать

...