février
2009
13e épisode
Nous avons décidé d’écrire chaque objet de la classe TPerson dans la base au fur et à mesure de sa création, de sa modification ou de sa suppression. Nous pourrions très bien mettre à jour la base de données au moment de quitter l’application, comme nous l’avons fait pour les fichiers-textes, mais avec le risque de perdre toutes nos mises à jour en cas de plantage. On accède aux fichiers-textes séquentiellement, ce qui ne permet pas la modification, l’insertion ou la suppression d’une ligne sans réécrire tout le fichier. C’est pourquoi nous écrivons les fichiers-textes en une seule fois au moment de quitter l’application. Par contre, une base de données SQL est spécialement conçue pour permettre l’accès direct à une ligne d’une table. Autant en profiter, et effectuer la mise à jour à chaque modification d’un objet TPerson.
2.2.3 – Visiteur TSQLUpdatePerson
Pour permettre la mise à jour de chaque objet TPerson, nous créons une nouvelle hiérarchie de classes.
Pour commencer, nous allons écrire le visiteur chargé de la mise à jour d’un enregistrement de la table People.
Rappelons que :
– TBizObjVisitor stocke la référence de l’objet appelant (FVisited) et implémente la méthode Finalize qui met à jour l’état de l’objet;
– TSQLFirebird gère la connexion à la base dans le constructeur et le destructeur.
Trois nouvelles classes sont apparues:
– TSQLWrite implémente VisitBizObj(Visited:TBizObj) qui exécute les méthodes Init et SetupParams du visiteur dans l’ordre adéquat;
– TSQLWritePerson vérifie que l’objet visité est bien de la classe TPerson (dans VisitBizObj);
– TSQLUpdatePerson implémente Init et SetupParams.
TBizObjVisitor et TSQLFirebird ont déjà été décrits précédemment. Voyons les trois autres:
- TSQLWrite
begin
inherited VisitBizObj(Visited);
Init; //implémenté dans TSQLUpdatePerson
SetupParams; //implémenté dans TSQLUpdatePerson
FQuery.ExecSQL;
Finalize; // implémenté dans TBizObjVisitor
end;
- TSQLWritePerson
begin
if not(Visited is TPerson) then
Exit;
inherited VisitBizObj(Visited); //ci-dessus dans TSQLWrite
end;
- TSQLUpdatePerson
begin
FQuery.SQL.Clear;
FQuery.SQL.Add('UPDATE PEOPLE SET');
FQuery.SQL.Add('LastName = :LastName,');
FQuery.SQL.Add('FirstName = :FirstName,');
FQuery.SQL.Add('BirthDate = :BirthDate');
FQuery.SQL.Add('WHERE OID = :OID;');
end;
procedure TSQLUpdatePerson.SetupParams;
var
IData: TPerson;
begin
IData := TPerson(FVisited);
FQuery.Params.ParamByName('OID').AsInteger := IData.OID;
FQuery.Params.ParamByName('LastName').AsString := IData.LastName;
FQuery.Params.ParamByName('FirstName').AsString := IData.FirstName;
FQuery.Params.ParamByName('BirthDate').AsDateTime := IData.BirthDate;
end;
Le visiteur sera appliqué à l’objet TPerson après son édition avec TFormPerson :
var
aPerson: TPerson;
begin
if ListBox1.ItemIndex < 0 then begin
MessageDlg('Sélectionnez une ligne', mtError, [mbOK], 0);
Exit;
end;
aPerson := TPerson(People.List.Items[ListBox1.ItemIndex]);
TFormPerson.Execute(aPerson);
if ExtractFileExt(CurrentFileName) = '.fdb' then begin
aPerson.AcceptBizObjVisitor(TSQLUpdatePerson.Create(CurrentFileName));
end;
DisplayList;
end;
En fait, au cous de la mise au point de l’application, j’ai été amené à écrire une version un peu plus sophistiquée de cette méthode :
var
aPerson: TPerson;
aPersonOld: TPerson;
Visitor: TSQLUpdatePerson;
begin
if ListBox1.ItemIndex < 0 then begin
MessageDlg('Sélectionnez une ligne', mtError, [mbOK], 0);
Exit;
end;
aPerson := TPerson(People.List.Items[ListBox1.ItemIndex]);
aPersonOld := TPerson.Create;
try
aPersonOld.OID := aPerson.OID;
aPersonOld.BirthDate := aPerson.BirthDate;
aPersonOld.FirstName := aPerson.FirstName;
aPersonOld.LastName := aPerson.LastName;
TFormPerson.Execute(aPerson);
if ExtractFileExt(CurrentFileName) = '.fdb' then
if aPerson.Compare(aPersonOld) > 0 then begin
Visitor := TSQLUpdatePerson.Create(CurrentFileName);
try
aPerson.AcceptBizObjVisitor(Visitor);
finally
Visitor.Free;
end;
end;
DisplayList;
finally
aPersonOld.Free;
end;
end;
Remarquez la nouvelle méthode Compare qui permet de comparer deux objets TPerson, afin de n’effectuer la requête SQL que s’il y a eu modification des données. L’implémentation de cette méthode dans TPerson est la suivante:
var
Count: Integer;
begin
Count := 0;
if FBirthDate <> TPerson(aBizObj).BirthDate then
inc(Count);
if FFirstName <> TPerson(aBizObj).FirstName then
inc(Count);
if FLastName <> TPerson(aBizObj).LastName then
inc(Count);
Result := Count;
end;
Le résultat est supérieur à 0 si un champ a été modifié.