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
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
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;
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. –
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! –
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;
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 –
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 –
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. –
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é.
Encore une fois, cela implique que beaucoup de modifications doivent être faites, mais j'apprécie la perspicacité de toute façon!Merci Pascal! –