2009-06-11 8 views
2

Dans mon application, j'ai différents formulaires qui utilisent la même source de données (donc les requêtes sont les mêmes), définis dans un module de données commun. La question est, est-il un moyen de savoir combien de fois ai-je ouvert une requête spécifique? En étant capable de faire cela, je pourrais éviter de fermer cette requête sans la fermer «partout ailleurs». Editer: Il est important de mentionner que j'utilise Delphi3 et ce n'est pas une seule requête mais plusieurs.Delphi & datasources partagées

Répondre

0

Vous pourriez avoir un TDataSet générique sur le datamodule partagé et le mettre sur le OnDataChange, en utilisant la propriété DataSet du paramètre de champ

dstDataSet: = Field.DataSet;

De cette façon, lorsque vous voulez fermer l'ensemble de données, fermer l'ensemble de données sur la datamodule, qui est un pointeur vers le DataSet correct sur une certaine forme vous n'avez même pas savoir

+0

Encore une fois, cela implique que beaucoup de modifications doivent être faites, mais j'apprécie la perspicacité de toute façon!Merci Pascal! –

3

Vous pouvez obtenir créatif en utilisant une approche addref/release like. Il suffit de créer quelques fonctions et une variable entière dans votre datamodule partagé pour faire de la magie, et assurez-vous d'appeler them..partial Code suit:

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; 

EDIT: Pour ce faire avec plusieurs requêtes, vous avez besoin un conteneur pour contenir les références de requête, et un moyen de les manipuler. un tList fonctionne bien pour cela. Vous devrez effectuer les modifications appropriées pour votre descendant TDataset, ainsi que créer une fonction FreeAndNil si vous utilisez une ancienne version de Delphi. Le concept que j'ai utilisé pour cela était de maintenir une liste de toutes les requêtes que vous demandez et de les manipuler par le handle qui est en fait l'index de la requête dans la liste. La méthode FreeUnusedQueries est là pour libérer tous les objets qui n'ont plus de référence ... cela peut aussi être fait dans le cadre de la méthode close, mais je l'ai séparé pour gérer les cas où une requête spécifique devrait être rouverte par un autre module.

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; 
+0

Merci skamradt, le problème avec cette approche est que je dois modifier beaucoup plus de code, car ce n'est pas une seule requête mais plusieurs. –

+0

Je vois votre point, assez malin, mais en appliquant cela, cela implique une reestructuration de plusieurs unités ce que je suis incapable de faire maintenant:/Je cherche quelque chose comme un quick-hack à appliquer directement * avant * I ferme une requête partagée. Mais merci quand même! –

4

L'idée est d'utiliser les DataLinks propriété du TDataSource.
Mais, comme il est protégé, vous devez y accéder. Une astuce courante consiste à créer un faux descendant juste pour le but de la coulée:

type 
    TDataSourceHack = class(TDataSource); 

Ensuite, vous l'utiliser comme:

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

Merci beaucoup François, c'est ce que je cherchais, malheureusement je n'ai pas mentionné que je travaillais avec Delphi3 :(mon erreur .. Vous ne pouvez pas utiliser cette méthode dans Delphi3 car le champ FDataLinks est privé et En revanche, dans Delphi6 vous avez la propriété publiée DataLinks que vous pouvez utiliser sans problème –

+0

Pour Delphi 3, vous pouvez essayer ce hack "plus sale" de HALLVARD VASSBOTN ...: http : //hallvards.blogspot.com/2004/06/hack-5-access-to-private-fields.html –

+0

Aaaggghh .. aucun moyen d'appliquer cette solution ni (ou peut-être que je l'ai fait mal), j'ai eu des violations d'accès exceptions pour tous les cas. –

0

Ok, une solution complètement différente ... qui devrait travailler pour Delphi 3.

Créez un nouvel objet descendant à partir de votre ensemble de données existant dans une nouvelle unité et ajoutez un comportement dans le nouvel objet. Malheureusement, Delphi 3 n'est pas disponible pour les tests, mais cela devrait fonctionner si vous pouvez trouver les bons points d'accès. Par exemple:

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; 

Ensuite, il suffit d'inclure l'unité dans votre module de données et modifier la référence à votre ensemble de données partagées (vous devrez également enregistrer celui-ci et l'ajouter à la palette si vous utilisez des composants). Une fois cela fait, vous n'aurez pas à apporter de modifications aux autres unités car l'ensemble de données est toujours un descendant de l'original. Ce qui fait que tout cela fonctionne, c'est la création de votre objet surchargé.

Questions connexes