Sign in Join
Wiki copytemporary

SQLdb Tutorial2/fr: what changed

Revision 1 to 2. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
11## Vue d'ensemble
22
33Si vous avez suivi le [[SQLdb Tutorial1/fr|Tutoriel SQLdb 1]], vous avez un grille basique montrant des informations provenant de la base de données. Maintenant que votre application marche, vous pouvez y ajouter certains raffinements.
44
55### Connexion dynamique à une base de données
66
77Jusqu'à maintenant, nous utilisions des nom de base de données, emplacement de base de données, nom d'utilisateur et mot de passe fixé pour simplifier. Comme indiqué, des applications "réelles" laissent normalement les utilisateurs spécifier leur propres nom d'utilisateur et mot de passe.
88
99Changeons la fiche de façon à pouvoir les spécifier : ajoutez deux [[TEdit/fr|TEdits]] depuis l'onglet standard. Mettez leur propriété Name à 'Username' et 'Password'. Définissez la propriété PasswordChar de 'Password' à * (l'astérisque) par sécurité vis à vis de personne qui regarderait par dessus votre épaule.
1010
1111Si vous voulez rendre plus facile (et moins sécurisé, bien sûr) de se connecter, vous pouvez définir la propriété Text de UserName avec un nom d'utilisateur valide de la base de données, tel que SYSDBA. Vous pouvez même définir la propriété Text de Password à une valeur par défaut telle que masterkey, simple pour le test sur une machine de développement si la sécurité n'est pas une préoccupation...
1212
1313Cosmétiquement, l'ajout de quelques étiquettes (*Label*) pour que les gens sachent ce qu'ils sont censés taper est utile.
1414
1515Aussi pour rendre plus facile la connexion à toute base de données exemple sur tout serveur Firebird/Interbase, nous ajoutons deux zone de texte pour le serveur et le chemin à la base de données. Ajoutons ces deux autres zones de texte et appelons-les ServerName et DatabaseName.
1616
1717Si vous voulez, vous pouvez définir la propriété 'Text' à des valeurs sensibles dans votre situation, p.ex. localhost et `C:\Program Files\Firebird\Firebird_2_5\examples\empbuild\EMPLOYEE.FDB`. Des étiquettes (*Labels*) pour expliquer ce que doit entrer l'utilisateur peuvent aider aussi.
1818
1919Pour clarifier, nous allons supprimer les informations de connexion de nos composants en conception : Dans le composant [[TSQLConnector/fr|TSQLConnector]], retirez tout les textes des propriétés UserName, Password, DatabaseName et HostName.
2020
2121Maintenant, finalement, nous avons besoin d'indiquer à notre composant de connexion à la base de données comment se connecter. Cela est uniquement nécessaire au début de l'exécution de l'application. Dans notre cas, le bouton existant 'Button1' est une bonne manière de mettre en place la connexion.
2222
2323Ajoutez le code :
2424
2525``` pascal
2626procedure TForm1.Button1Click(Sender: TObject);
2727begin
2828 SQLQuery1.Close;
2929 //Connection settings for Firebird/Interbase database
3030 //only needed when we have not yet connected:
3131 if not DBConnection.Connected then
3232 begin
3333 DBConnection.HostName := ServerName.Text;
3434 DBConnection.DatabaseName := DatabaseName.Text;
3535 DBConnection.Username := UserName.Text;
3636 DBConnection.Password := Password.Text;
3737 // Now we've set up our connection, visually show that
3838 // changes are not possibly any more
3939 ServerName.ReadOnly:=true;
4040 DatabaseName.ReadOnly:=true;
4141 UserName.ReadOnly:=true;
4242 Password.ReadOnly:=true;
4343 end;
4444 SQLQuery1.SQL.Text:= 'select * from CUSTOMER';
4545 DBConnection.Connected:= True;
4646 SQLTransaction1.Active:= True;
4747 SQLQuery1.Open;
4848end;
4949```
5050
5151Maintenant exécutez et testez si vous êtes connectés.
5252
5353#### SQLite, autres bases de données
5454
5555Adaptez la propriété Text dans le TEdit comme demandé ; p.ex. `employee.sqlite` pour SQLite.
5656
5757For SQLite, la spécification des HostName, Username et password n'a pas de sens, donc vous pouvez omettre ces TEddits, commentez l'affectation des valeurs correspondantes dans DBConnection dans le code du dessus. Pour FireBird incorporé, forcez en dur le UserName à SYSDBA ; cela ne fera aucun mal si SQLite est utilisé.
5858
5959Le code ressemblera à quelque chose comme cela :
6060
6161``` pascal
6262procedure TForm1.Button1Click(Sender: TObject);
6363begin
6464 SQLQuery1.Close;
6565 //Connection settings for embedded databases
6666 //only needed when we have not yet connected:
6767 if not DBConnection.Connected then
6868 begin
6969 DBConnection.DatabaseName := DatabaseName.Text;
7070 DBConnection.UserName := 'SYSDBA'; //Firebird embedded needs this; doesn't harm if using SQLite
7171 // Now we've set up our connection, visually show that
7272 // changes are not possibly any more
7373 DatabaseName.ReadOnly:=true;
7474 end;
7575 SQLQuery1.SQL.Text:= 'select * from CUSTOMER';
7676 DBConnection.Connected:= True;
7777 SQLTransaction1.Active:= True;
7878 SQLQuery1.Open;
7979end;
8080```
8181
8282### Filtrage de données
8383
8484Souvent, une table contient une énorme quantité de données que l'utilisateur ne veut(ou ne doit) pas voir (et cela prend beaucoup de temps à requêter et voyage à travers le réseau). Supposons que seuls les clients des USA devraient être affichés. En conséquence, l'ordre SQL dans 'SQLQuery1' ressemblera à quelque chose comme ceci :
8585
8686``` SQL
8787select * from CUSTOMER where COUNTRY = 'USA'
8888```
8989
9090... qui devrait être transformé en quelque chose comme cela dans notre code :
9191
9292``` pascal
9393SQLQuery1.SQL.Text := 'select * from CUSTOMER where COUNTRY = 'USA'';
9494```
9595
9696Il y a deux raisons pour lesquelles nous n'utilisaeraon pas cette ordre dans notre exemple d'application :
9797
9898D'abord il y a un problème avec l'emploi des aapostrophes. Le compilateur interprétera cela l'apostrophe avant USA comme une apostrophe de fermeture (la première apostrophe est devant le SELECT * FROM...), ainsi l'ordre SQL va devenir invalide. Solution : il faut doubler les apostrophes intérieures :
9999
100100``` pascal
101101SQLQuery1.SQL.Text := 'select * from CUSTOMER where COUNTRY = ''USA''';
102102```
103103
104104Ensuite, raison plus importante dans les faits, nous ignorons probablement ce quelles contraintes l'utilisateur voudra filtrer. Nous ns voulons pas limiter la flexibilité de l'utilisateur.
105105
106106Pour obtenir cette flexibilité, nous changeons en premier notre ordre SQL et remplaçons 'USA' par une marque substitutive (*placeholder*, un paramètre pour parler SQL) : changez la procédure Button1click et remplacez :
107107
108108``` pascal
109109SQLQuery1.SQL.Text := 'select * from CUSTOMER';
110110```
111111
112112par :
113113
114114``` pascal
115115SQLQuery1.SQL.Text:= 'select * from CUSTOMER where COUNTRY = :COUNTRY';
116116```
117117
118118Dasn SQLDB de FPC, le paramètre SQL est marqué par un caractère deux-points (d'autres langages/environnements utilisent une autre convention comme ?). Pour permettre à l'utilisateur d'entrer une valeur pour le filtre, nous plaçons un composant *TEdit* sur notre fiche. Supprimez a valeur dans la propriété 'Text'. Nous pouvons maintenant prendre le texte entré dans le TEdit et remplir le paramètre SQL COUNTRY en utilisant la propriété 'Params' du TSQLQuery. Ajoutez ce qui suit dans l'instruction précédente :
119119
120120``` pascal
121121SQLQuery1.Params.ParamByName('COUNTRY').AsString := Edit1.Text;
122122```
123123
124124Le paramètre peut être spécifié par sa position ou son nom. L'utilisation du nom améliorera la lisibilité du code source, et évidemment aide si vous insérez plus de paramètre au milieu des paramètres existants.
125125
126126Nous utilisons '.AsString' pour affecter une valeur chaîne au paramètre ; il y a des affectation de propriété équivalente pour les paramètres entiers, booléens etc.
127127
128128Jusqu'à maintenant, le code nous forçe à utiliser un filtre. Si un utilisateur spécifie une valeur vide dans la zone de saisie, aucun enregistrement ne sera affiché. Ce n'est sans doute pas ce que nous voulons. Testons la valeur vide et construisons la requête en conséquence. Nous devrions nous retrouver avec une procédure comme celle-ci :
129129
130130``` pascal
131131procedure TForm1.Button1Click(Sender: TObject);
132132begin
133133 SQLQuery1.Close;
134134 //Connection settings for Firebird/Interbase database
135135 //only needed when we have not yet connected:
136136 if not DBConnection.Connected then
137137 begin
138138 DBConnection.HostName := ServerName.Text;
139139 DBConnection.DatabaseName := DatabaseName.Text;
140140 DBConnection.Username := UserName.Text;
141141 DBConnection.Password := Password.Text;
142142 // Now we've set up our connection, visually show that
143143 // changes are not possibly any more
144144 ServerName.ReadOnly:=true;
145145 DatabaseName.ReadOnly:=true;
146146 UserName.ReadOnly:=true;
147147 Password.ReadOnly:=true;
148148 end;
149149 // Show all records, or filter if user specified a filter criterium
150150 if Edit1.Text='' then
151151 SQLQuery1.SQL.Text := 'select * from CUSTOMER'
152152 else
153153 begin
154154 SQLQuery1.SQL.Text := 'select * from CUSTOMER where COUNTRY = :COUNTRY';
155155 SQLQuery1.Params.ParamByName('COUNTRY').AsString := Edit1.Text;
156156 end;
157157 DBConnection.Connected:= True;
158158 SQLTransaction1.Active:= True;
159159 SQLQuery1.Open;
160160end;
161161```
162162
163163Maintenant vous pouvez jouer un peu avec le filtrage en utilisant Edit1. Si vous entrez un pays qui n'est pas présent dans la base de données, une grille affichée est vide.
164164
165165### Gestion des erreurs
166166
167167L'application devrait tourner mais parfois des problèmes arrivent. Les bases de données, même les bases incorporées, peuvent planter (i.e. quand le serveur de base de données plante, le disque est plein, ou juste provoqué par un bug), laissant l'application en suspens.
168168
169169L'accès à une base de données (tout processus externe, en vrai) devrait donc *toujours* être intégré dans une construction try ... except et/ou try ... finally. Cela garantit que les erreurs de bases de données sont traitées et que l'utilisateur n'est pas laissé à l'abandon. Une routine rudimentaire pour notre exemple peut ressembler à ceci :
170170
171171``` pascal
172172begin
173173 try
174174 SQLQuery1.Close;
175175 ...
176176 SQLQuery1.Open;
177177 except
178178 //We could use EDatabaseError which is a general database error, but we're dealing with Firebird/Interbase, so:
179179 on E: EDatabaseError do
180180 begin
181181 MessageDlg('Error','A database error has occurred. Technical error message: ' + E.Message,mtError,[mbOK],0);
182182 Edit1.Text:='';
183183 end;
184184 end;
185185end;
186186```
187187
188188#### SQLite, PostgreSQL, autres bases de données
189189
190190Vous pouvez soit utiliser la plus générique EDatabaseError, ou, si disponible, votre propre dérivé de EDatabaseError, si vous avez besoin de plus de détail. P.ex. SQLite et le pilote PostgreSQL dans FPC 2.6.1 et antérieur n'ont pas de E*DatabaseError spécialisé; vous devez utiliser EDatabaseError. PostgreSQL sur FPC du tronc (version de développement) a un dérivé EPQDatabaseError.
191191
192192## Edition des données utilisant la grille
193193
194194### Edition
195195
196196Jusqu'à maintenant, si vous essayiez d'éditer des données dans la grille, les modifications ne pourront pas être enregistrés. Ceci parce que le *SQLQuery1* n'est pas construit pour envoyer les changements vers la transaction de base de données au bon moment.
197197
198198Nous avons besion de corriger cela et donc de faire le commit de la base de données, ainsi tous les changements seront écrit. Pour ceci, vous devrez utiliser du code comme ceci :
199199
200200``` pascal
201201SQLQuery1.ApplyUpdates; //Pass user-generated changes back to database...
202202SQLTransaction1.Commit; //... and commit them using the transaction.
203203//SQLTransaction1.Active now is false
204204```
205205
206206Nous voulons garantir que toutes les éditions (insertions, mises à jour, suppressions) sont écrites dans la base de données :
207207
208208- quand l'utilisateur change le critère de filtrage et presse le bouton poutr interroger la base de données.
209209- quand la fiche est fermée.
210210
211211Il est pertinent de faire une procédure séparée pour ceci qui est appelée pour ces deux instances. Allez au code et ajoutez une ligne vide ici :
212212
213213``` pascal
214214 TForm1 = class(TForm)
215215 Button1: TButton;
216216 Datasource1: TDatasource;
217217 DBGrid1: TDBGrid;
218218 Edit1: TEdit;
219219 DBConnection: TIBConnection;
220220 SQLQuery1: TSQLQuery;
221221 SQLTransaction1: TSQLTransaction;
222222*****insert the empty line here****
223223 procedure Button1click(Sender: TObject);
224224 procedure Formclose(Sender: TObject; var Closeaction: Tcloseaction);
225225 private
226226```
227227
228228puis tapez :
229229
230230``` pascal
231231 procedure SaveChanges;
232232```
233233
234234pressez shift-ctrl-c (combinaison par défaut) pour laisser la complétion de code créer le corps de la procédure correspondante.
235235
236236Nous avons besoin d'ajouter la gestion d'erreur et contrôler que la transaction est active - souvenez-vous, ce code est aussi appelé quand le bouton est actionné la première fois, quand la transaction n'est pas encore active. Nous obtenons :
237237
238238``` pascal
239239procedure Tform1.SaveChanges;
240240// Saves edits done by user, if any.
241241begin
242242 try
243243 if SQLTransaction1.Active then
244244 // Only if we are within a started transaction;
245245 // otherwise you get "Operation cannot be performed on an inactive dataset"
246246 begin
247247 SQLQuery1.ApplyUpdates; //Pass user-generated changes back to database...
248248 SQLTransaction1.Commit; //... and commit them using the transaction.
249249 //SQLTransaction1.Active now is false
250250 end;
251251 except
252252 on E: EDatabaseError do
253253 begin
254254 MessageDlg('Error', 'A database error has occurred. Technical error message: ' +
255255 E.Message, mtError, [mbOK], 0);
256256 Edit1.Text := '';
257257 end;
258258 end;
259259end;
260260```
261261
262262Maintenant nous avons besoin d'appeler cette procédure aux moments appropriés :
263263
264264``` pascal
265265procedure Tform1.Button1click(Sender: TObject);
266266begin
267267 SaveChanges; //Saves changes and commits transaction
268268 try
269269 SQLQuery1.Close;
270270....
271271```
272272
273273et
274274
275275``` pascal
276276procedure Tform1.Formclose(Sender: TObject; var Closeaction: Tcloseaction);
277277begin
278278 SaveChanges; //Saves changes and commits transaction
279279 SQLQuery1.Close;
280280....
281281```
282282
283283Maintenant testez et voyez si les modifications réalisées dans la grille sont enregistrées dans la base de données.
284284
285285### Masquage de la colonne de clé primaire
286286
287287Souvent, vous ne voulez pas que vos utilisateurs voient les clés primaires auto-incrémentées car elles ne servent qu'à maintenir l'intégrité référentielle. Si les utilisateurs les voient, ils voudront peut-être essayer de modifier les numéros, se fâcher lorsque les chiffres changent, qu'il y ait des lacunes dans les chiffres, etc.
288288
289289Dans notre exemple, CUST_NO est la clé primaire, avec du contenu auto-généré par Firebird en utilisant des triggers et un générateur (séquence). ,Ceci veut dire que vous pouvez insérer un nouvel enregistrement sans spécifier le champ CUST_NO ; Firebird créera la valeur du champ automatiquement.
290290
291291Nous pouvons changer simplement notre propriété SQLQuery1.SQL.Text pour ne pas inclure CUST_NO, mais cela amènera à des problèmes lors de l'édition des données - la clé primaire est demandée pour identifier l'enregistement/ ligne en question.
292292
293293Donc utilisons une astuce pour récupérer toutes les colonnes/champs mais empêcher la grille d'afficher le premier champ, CUST_NO : dans la procédure Button1Click, ajoutez le code comme cela :
294294
295295``` pascal
296296procedure Tform1.Button1click(Sender: TObject);
297297begin
298298...
299299 SQLQuery1.Open;
300300 // Hide the primary key column which is the first column in our queries.
301301 // We can only do this once the DBGrid has created the columns
302302 DBGrid1.Columns[0].Visible:=false;
303303```
304304
305305Recompilez et contrôlez pour voir si la colonne de clé primaire est effectivement cachée.
306306
307307#### SQLite, autres bases de données
308308
309309- Autres base de données : de nombreuses autres bases de données utilisent un type de champ 'autonumber' ou 'autoinc' pour fournir du contenu de champ auto-généré. Essayez de changer votre définition de table pour voir si cela fonctionne.
310310- Sqlite : l'exmple du dessus fonctionne pour SQLite car nous utilisons une clé primaire entière. Voir la the [documentation](http://www.sqlite.org/autoinc.html) pour des détails.
311311
312312### Insertion de nouvelles données
313313
314314Si vous insérez de nouveaux enregistements/lignes sans aucune information CUST_NO, vous pouvez avoir remarqué que vous obtenez le message d'erreur : `Field CUST_NO is required, but not supplied`. Ceci survient aussi si vous cachez la colonne CUST_NO comme dans la section précédente.
315315
316316La raison : Lazarus pense que CUST_NO est requis. Cela n'est pas étrange, car c'est une clé primaire et la définition de table sous-jacente dans la base de données dit qu'il est requis.
317317
318318Si nous pouvons intimer à Lazarus que ce champ n'est pas actuellement requis, nous pouvons passer des valeurs vides (=valeurs à NULL) à la base de données. Heureusement, un objet champ de requête a une propriété *Required* qui sert exactement à cela.
319319
320320Modifiez le code en quelque chose comme :
321321
322322``` pascal
323323 SQLQuery1.Open;
324324 {
325325 Make sure we don't get problems with inserting blank (=NULL) CUST_NO values, e.g.:
326326 Field CUST_NO is required, but not supplied
327327 We need to tell Lazarus that, while CUST_NO is a primary key, it is not required
328328 when inserting new records.
329329 }
330330 SQLQuery1.FieldByName('CUST_NO').Required:=false;
331331 // Hide the primary key column which is the first column in our queries.
332332 // We can only do this once the DBGrid has created the columns
333333 DBGrid1.Columns[0].Visible:=false;
334334```
335335
336336### Suppression de données
337337
338338Vous pouvez laisser les utilisateurs employer la souris pour cela. Vous n'avez même pas besoin de code une seule ligne pour cette fonctionnalité.
339339
340340Sur l'onglet 'Data controls', sélectionner le composant *TDBNavigator* et posez-le sur la fiche, au dessus de la grille.
341341
342342Pour indiquer à quoi est relié le navigateur, mettez votre composant DataSource (DataSource1) dans sa propriété DataSource en utilisant l'inspecteur d'objet.
343343
344344Maintenant vous pouvez utiliser le bouton sur le *DBNavigator* pour supprimer des enregistrements, mais aussi pour en insérer et vous déplacer parmi les enregistrements. Aussi, en éditant les cellules/champs, vous pouvez utiliser le bouton *Cancel* pour annuler vos éditions.
345345
346-Pour permettre à l'utilisateur de supprimer la ligne sur laquelle ils sont dans la grille en utilisant la touche <span class="kbd">Delete</span>, ajoutez l'unité *LCLType* (elle contient les définitions des codes de touche) à votre clause uses :
346+Pour permettre à l'utilisateur de supprimer la ligne sur laquelle ils sont dans la grille en utilisant la touche `Delete`, ajoutez l'unité *LCLType* (elle contient les définitions des codes de touche) à votre clause uses :
347347
348348``` pascal
349349uses
350350 Classes, SysUtils, sqldb, pqconnection, DB, FileUtil, Forms,
351351 Controls, Graphics, Dialogs, DBGrids, StdCtrls, DbCtrls, LCLType;
352352```
353353
354-... il faut coder l'événement KeyUppour la grille, qui survient quand une touche est relâchée dans la grille. Toutefois; nous avons besoin de contrôler que l'utilisateur n'est pas en train de modifier un champ - comme il peut utiliser la touche <span class="kbd">Delete</span> pour supprimer des lettres plutôt que l'enregistrement sur lequel il travaille.
354+... il faut coder l'événement KeyUppour la grille, qui survient quand une touche est relâchée dans la grille. Toutefois; nous avons besoin de contrôler que l'utilisateur n'est pas en train de modifier un champ - comme il peut utiliser la touche `Delete` pour supprimer des lettres plutôt que l'enregistrement sur lequel il travaille.
355355
356356Sélectionnez la grille et allez sur les événements pour créer l'événement OnKeyUp comme ceci :
357357
358358``` pascal
359359procedure TForm1.DBGrid1KeyUp(Sender: TObject; var Key: Word; Shift: TShiftState
360360 );
361361begin
362362 // Check for del key being hit and delete the current record in response
363363 // as long as we're not editing data
364364 if (key=VK_DELETE) and (not(DBGrid1.EditorMode)) then
365365 begin
366366 //... delete current record and apply updates to db:
367367 SQLQuery1.Delete;
368368 SQLQuery1.ApplyUpdates;
369369 end;
370370end;
371371```
372372
373-> **Note:** Par défaut, dans la propriété Options du TDBGrid, dgDisableDelete est mise à False, ce qui veut dire que l'utilisateur peut supprimer un enregistrement avec la combinaison <span class="kbd">ctrl</span>+<span class="kbd">delete</span>. Vous pouvez ne pas désirer ce comportement.
373+> **Note:** Par défaut, dans la propriété Options du TDBGrid, dgDisableDelete est mise à False, ce qui veut dire que l'utilisateur peut supprimer un enregistrement avec la combinaison `ctrl`+`delete`. Vous pouvez ne pas désirer ce comportement.
374374
375375## Résumé
376376
377377Si vous avez tout suivi jusqu'à maintenant, vous pouvez récupérer des données de la base, les filtrer, les modifier, les supprimer dans la grille. Votre code ressemble à quelque chose comme cela.
378378
379379``` pascal
380380unit sqldbtutorial1unit;
381381
382382{$mode objfpc}{$H+}
383383
384384interface
385385
386386uses
387387 Classes, SysUtils, sqldb, pqconnection, DB, FileUtil, Forms,
388388 Controls, Graphics, Dialogs, DBGrids, StdCtrls, DbCtrls, LCLType;
389389type
390390
391391 { TForm1 }
392392
393393 TForm1 = class(TForm)
394394 Button1: TButton;
395395 DatabaseName: TEdit;
396396 Datasource1: TDatasource;
397397 DBGrid1: TDBGrid;
398398 Dbnavigator1: Tdbnavigator;
399399 Edit1: TEdit;
400400 Label2: Tlabel;
401401 Label3: Tlabel;
402402 Label4: Tlabel;
403403 Label5: Tlabel;
404404 Password: TEdit;
405405 UserName: TEdit;
406406 ServerName: TEdit;
407407 DBConnection: TIBConnection;
408408 Label1: TLabel;
409409 SQLQuery1: TSQLQuery;
410410 SQLTransaction1: TSQLTransaction;
411411 procedure SaveChanges;
412412 procedure Button1click(Sender: TObject);
413413 procedure Formclose(Sender: TObject; var Closeaction: Tcloseaction);
414414 private
415415 { private declarations }
416416 public
417417 { public declarations }
418418 end;
419419
420420var
421421 Form1: TForm1;
422422
423423implementation
424424
425425{$R *.lfm}
426426
427427{ TForm1 }
428428
429429procedure Tform1.Savechanges;
430430// Saves edits done by user, if any.
431431begin
432432 try
433433 if SQLTransaction1.Active then
434434 // Only if we are within a started transaction
435435 // otherwise you get "Operation cannot be performed on an inactive dataset"
436436 begin
437437 SQLQuery1.ApplyUpdates; //Pass user-generated changes back to database...
438438 SQLTransaction1.Commit; //... and commit them using the transaction.
439439 //SQLTransaction1.Active now is false
440440 end;
441441 except
442442 on E: EDatabaseError do
443443 begin
444444 MessageDlg('Error', 'A database error has occurred. Technical error message: ' +
445445 E.Message, mtError, [mbOK], 0);
446446 Edit1.Text := '';
447447 end;
448448 end;
449449end;
450450
451451procedure TForm1.DBGrid1KeyUp(Sender: TObject; var Key: Word; Shift: TShiftState
452452 );
453453begin
454454 // Check for del key being hit and delete the current record in response
455455 // as long as we're not editing data
456456 if (key=VK_DELETE) and (not(DBGrid1.EditorMode)) then
457457 begin
458458 //... delete current record and apply updates to db:
459459 SQLQuery1.Delete;
460460 SQLQuery1.ApplyUpdates;
461461 end;
462462end;
463463
464464procedure Tform1.Button1click(Sender: TObject);
465465begin
466466 SaveChanges; //Saves changes and commits transaction
467467 try
468468 SQLQuery1.Close;
469469 //Connection settings for Firebird/Interbase database
470470 //only needed when we have not yet connected:
471471 if not DBConnection.Connected then
472472 begin
473473 DBConnection.HostName := ServerName.Text;
474474 DBConnection.DatabaseName := DatabaseName.Text;
475475 DBConnection.Username := UserName.Text;
476476 DBConnection.Password := Password.Text;
477477 // Now we've set up our connection, visually show that
478478 // changes are not possibly any more
479479 ServerName.ReadOnly:=true;
480480 DatabaseName.ReadOnly:=true;
481481 UserName.ReadOnly:=true;
482482 Password.ReadOnly:=true;
483483 end;
484484 // Show all records, or filter if user specified a filter criterium
485485 if Edit1.Text='' then
486486 SQLQuery1.SQL.Text := 'select * from CUSTOMER'
487487 else
488488 begin
489489 SQLQuery1.SQL.Text := 'select * from CUSTOMER where COUNTRY = :COUNTRY';
490490 SQLQuery1.Params.ParamByName('COUNTRY').AsString := Edit1.Text;
491491 end;
492492 DBConnection.Connected := True;
493493 SQLTransaction1.Active := True; //Starts a new transaction
494494 SQLQuery1.Open;
495495 {
496496 Make sure we don't get problems with inserting blank (=NULL) CUST_NO values, i.e. error message:
497497 "Field CUST_NO is required, but not supplied"
498498 We need to tell Lazarus that, while CUST_NO is a primary key, it is not required
499499 when inserting new records.
500500 }
501501 SQLQuery1.FieldByName('CUST_NO').Required:=false;
502502 {
503503 Hide the primary key column which is the first column in our queries.
504504 We can only do this once the DBGrid has created the columns
505505 }
506506 DBGrid1.Columns[0].Visible:=false;
507507 except
508508 // EDatabaseError is a general error;
509509 // you could also use one for your specific db, e.g.
510510 // use EIBDatabaseError for Firebird/Interbase
511511 on E: EDatabaseError do
512512 begin
513513 MessageDlg('Error', 'A database error has occurred. Technical error message: ' +
514514 E.Message, mtError, [mbOK], 0);
515515 Edit1.Text := '';
516516 end;
517517 end;
518518end;
519519
520520procedure Tform1.Formclose(Sender: TObject; var Closeaction: Tcloseaction);
521521begin
522522 SaveChanges; //Saves changes and commits transaction
523523 SQLQuery1.Close;
524524 SQLTransaction1.Active := False;
525525 DBConnection.Connected := False;
526526end;
527527
528528end.
529529```
530530
531531## Base de données incorporée sans modification de code
532532
533533### Firebird sur Windows
534534
535535Un bonus pour les utilisateurs de Firebird sur Windows ; si vous avez suivi ce tutoriel (même si vous n'avez fait que l'exemple de base), vous avez renommé la bibliothèque incorporée de Firebird `fbembed.dll` en `fbclient.dll`. avec ceci, Lazarus se connectera aux serveurs Firebird normaux (sur une machine distante ou sur votre machine locale). Toutefois, vous pouvez aussi copier la base de données `employee.fdb` dans votre dossier d'application, exécuter l'application, effacer le TEdit *Server name* et utiliser Firebird incorporé pour vous connecter directement au fichier de la base de données, sans configuration de serveur.
536536
537537Ceci est génial si vous souhaitez déployer des applications de base de données vers les utilisateurs finaux, mais ne souhaitez pas avoir du mal à installer des serveurs (vérifier si un serveur est déjà installé, s'il s'agit de la bonne version, faire en sorte que les utilisateurs vérifient les pare-feu, etc.).
538538
539539Voir [[Firebird embedded/fr|Firebird incorporé]] pour plus de détails.
540540
541541Note (non vérifiée) : Depuis 2011, FPC tente de charger d'abord `fbembed.dll`, donc vous n'avez pas besoin de renommer `fbclient.dll` pour que cela fonctionne.
542542
543543### Firebird sur Linux/OSX/Unix
544544
545545Il doit y avoir un moyen pour que cela fonctionne sur Linux / OSX. Voir [[Firebird/fr|Firebird]] pour les conseils et les liens. Les mises à jour du wiki sont les bienvenues.
546546
547547### SQLite
548548
549549Certes, SQLite offre une fonctionnalité incorporée mais d'un autre côté, il ne permet pas de configuration client/serveur. En suivant le tutoriel du haut, vous pouvez voir cela qu'en basculant les bases de données (p.ex. SQLite et Firebird) ne fait pas tant de travail que cela.
550550
551551### Autres bases de données
552552
553553Votre base de données peut offrir des fonctionnalités similaires. Des mises à jour de ce Wiki pour d'autres SGBD sont les bienvenues.
554554
555555## Voir aussi
556556
557557- [[SQLdb Tutorial0/fr|SQLdb Tutorial0]] : Instructions pour configurer les tables et les données d'exemple pour la série de tutoriels.
558558- [[SQLdb Tutorial1/fr|SQLdb Tutorial1]] : 1re partie de la série de tutoriels sur les bases de données, montrant comment configurer une grille pour afficher les données.
559559- [[SQLdb Tutorial2/fr|SQLdb Tutorial2]] : 2e partie de la série de tutoriels, montrant l'édition, l'insertion, etc.
560560- [[SQLdb Tutorial3/fr|SQLdb Tutorial3]] : 3e partie de la série de tutoriels, montrant comment développer pour des bases de données multiples et utiliser une fiche de connexion.
561561- [[SQLdb Tutorial4/fr|SQLdb Tutorial4]] : 4e partie de la série de tutoriels, montrant comment utiliser les modules de données.
562562- [[Lazarus Database Overview/fr|Vue d'ensemble des bases de données pour Lazarus]] : Information sur les bases de données supportées par Lazarus. Redirige vers des notes spécifiques à certaines bases de données.
563563- [[SQLdb Package/fr|Paquet SQLdb]] : Information sur le paquetage SQLdb.
564564- [[SQLdb Programming Reference/fr|Référence de programmation SQLdb]] : Une vue d'ensemble de l'interaction entre les composants de bases de données SQLdb.
565565- [[SqlDBHowto/fr|SqlDBHowto]] : Information sur l'utilisation du paquet SQLdb.
566566- [[Working With TSQLQuery/fr|Travailler avec TSQLQuery]] : Informations sur TSQLQuery.
567567- [utilisation des paramètres](http://www.freepascal.org/docs-html/fcl/sqldb/usingparams.html)
568568
569569---
570570*From the Free Pascal wiki, page "SQLdb Tutorial2/fr", as it stood on 2020-02-26 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history