Interbase Borland Data Provider
April 5, 2017 | Author: Anonymous Wpl47Bwu4 | Category: N/A
Short Description
Download Interbase Borland Data Provider...
Description
Interbase Borland Data Provider - John COLIBRI.
abstract:utilisation du Borland Data Provider sous Windows Forms pour gérer en Delphi 8 des données Interbase mots clé:BDP - Borland Data Provider - .Net SDK Windows Forms - Delphi 8 - Interbase - Firebird logiciel utilisé: Windows XP, Delphi 8, Interbase 6 matériel utilisé: Pentium 1.400Mhz, 256 M de mémoire champ d'application: Delphi 8 sur Windows, Interbase, Firebird niveau: débutant Delphi et Base de Données plan: o Introduction o Architecture o Connexion à la base o Créer une Table o Ajouter des Données o Lire et Afficher o Modifier des Données o Evaluation o Télécharger les Exemples o Conclusion
1 - Introduction J'ai choisi de présenter à Borcon 2004 les différents moyens d'utiliser Interbase:
pour Delphi 5 à 6, les API, le BDE et Sql Links, Interbase Express, dbExpress et Ado pour Delphi 8: o en mode VCL.Net, dbExpress.Net, Ibx.Net o en mode Windows Forms, Ado.Net et le BDP
Cet article va se concentrer sur le mode Windows Forms et le Borland Data Provider. Pour les autres façons d'utiliser Interbase, vous pouvez consulter sur ce site:
le tutorial interbase: comment utiliser des bases de données en mode Client Serveur (Delphi 6, Ibx). L'article d'initiation le plus complet Interbase dbExpresss: le mode dbExpress (Delphi 6, dbExpress). Le mode qui permet le mieux de comprendre l'architecture Ado.Net qui en est directement issue
Interbase Ibx.Net: le portage sous .Net de la mécanique Ibx (Delphi 8, Ibx.Net). Le moyen le plus simple d'utiliser Interbase et Delphi 8. Contient aussi un comparatif de toutes ces architectures avec les schémas correspondants Interbase dbExpress.Net: le portage sous .Net de la mécanique dbExpress (Delphi 8, dbExpress.Net). L'utilisation des techniques VCL pour Interbase ET pour les autres serveurs (Oracle, Sql Server, MyBase etc)
Nous nous adressons pour cet article à un programmeur Delphi ayant une idée élémentaire de Delphi: Palette, Inspecteur, OnClick. Tout le reste sera expliqué. Nous supposons:
que Delphi 8 est installé (la version "développeur": pas la version "étudiant" qui n'a pas les bases de données, et pas besoin de la version "Entreprise" ou "Architecte", mais tout marche aussi avec ces deux dernières) qu'Interbase est installé (voyez le tutorial interbase qui détaille cette installation). J'ai utilisé la version Interbase 6 que j'ai installée et que j'utilise couremment avecDelphi 6, mais tout fonctionne bien sûr avec les versions 7 et FireBird.
2 - Architecture Une fois les librairies .Net installées, nous pouvons utiliser des Serveurs de bases de données en utilisant une couche appelée Ado.Net. Cette couche définit des composant pour communiquer avec des "sources de données". Ces sources sont très générales: des courriers Outlook, des données Excel et des données provenant d'un Serveur Sql. Pour les bases de données, Ado.Net permet de gérer:
de façon native o "Sql Data Provider" pour Sql Server en ajoutant des modules supplémentaires, d'autres bases de données: o pour Oracle, le module "Oracle Data Provider" o pour les serveurs pour lesquels existe un pilote ODBC, le module "ODBC Data Provider"
o o
pour les serveurs ayant un pilote OleDb COM, le module "OleDb Data Provider" le module "Borland Data Provider" qui est un provider générique pour plusieurs serveurs, tels que Sql Server, Oracle, DB2, FireBird et Interbase.
Pour accéder à Interbase, nous pouvons donc:
acheter un pilote ODBC (EasySoft) acheter un pilote OleDb (IbProvider) utiliser le BDP fourni avec Delphi 8
Notez aussi que le BDP est un module .Net général: il peut être utilisé avec n'importe quel langage qui communique avec les librairies .Net (Delphi 8, bien sûr, mais aussi les autres langages via les divers outils de développement). L'architecture générale a donc l'allure suivante:
3 - La connection 3.1 - Préparation Le BDP ne sait pas créer de base vierge. Seul Ibx, en mode Delphi 6, ou Ibx.Net en mode Delphi 8 peuvent le faire. Nous allons donc utiliser une base créée auparavant, en la copiant dans un répertoire proche pour éviter de la rechercher nichées dans des répertoires dépendant de chaque installation. Nous allons: créer un répertoire _DATA au même niveau que nos sources (dans n'importe quel répertoire qui vous convient) copier une base Interbase dans ce répertoire. Par exemple INSTITUT_PASCAL.GDB provenant de nos tutoriaux antérieurs, ou EMPLOYEE.GDB provenant de "FICHIERS COMMUNS" etc renommer cette base INSTITUT_PASCAL_5.GDB
3.2 - La connection Commençons par nous connecter à note base Interbase: lancez Delphi 8 créez une nouvelle application en cliquant "Fichiers | Nouveau | Windows Forms" et renommez-la "p_ib_bdp_connection" dans la page "Borland Data Provider" sélectionnez un BdpConnection:
et posez-le sur le Forme comme d'habitude, le BdpConnection est affiché sous la Windows Forms:
sélectionner BdpConnection1, et avec un Click droit souris, ouvrez l'Editeur de Connections. Par défaut il affiche les propriétés du serveur DB2:
tapez les propriétés de notre base:
sélectionnez le pilote IbConn1 tapez le chemin _DATA\INSTITUT_PASCAL_5.GDB
testez la connection en cliquant "Test" Si le chemin et le nom de la base sont corrects, un dialogue "Connection Successful" apparaît. Fermez-le
fermez le dialogue de connection en cliquant "OK"
Notez que
j'ai eu le plaisir de voir que le "UserName" et "Password" sont déjà remplis, et que le LoginPrompt est False par défaut. Passer sa journée, sur sa propre machine, à taper les sempiternels "SYSDBA" et "masterkey" n'est pas particulièrement productif. le dialecte 3 est déjà initialisé (nous avons créé notre base avec ce dialecte).
Delphi a rempli les propriétés ConnectionString et ConnectionOptions dans l'Inspecteur d'Objet:
ConnectionString contient: assembly=Borland.Data.Interbase, Version=1.5.0.0, Culture=neutral, PublicKeyToken=91d62ebb5b0d1b1b; vendorclient=gds32.dll; database=..\_data\INSTITUT_PASCAL_5.GDB; provider=Interbase; username=sysdba; password=masterkey
ConnectionOption contient: waitonlocks=False; commitretain=False; sqldialect=3; transaction isolation=ReadCommitted; servercharset=; rolename=myrole
4 - Créer et remplir une Table 4.1 - Principe Nous allons créer une table contenant pour chaque formation:
un code (par exemple 8) un nom (par exemple "Delphi Interbase") le nombre de jours (par exemple 3) un prix (par exemple 1.400)
La syntaxe de la requête SQL à envoyer vers le Server est la suivante: CREATE TABLE formations_5 (f_numero INTEGER, f_nom CHARACTER(23), f_jours INTEGER, f_prix NUMERIC(5, 2) )
Pour envoyer cette requête vers le Serveur:
nous utilisons un BdpConnection qui assurera la connection vers le Serveur nous créons un objet BdpCommand en utilisant:
my_c_bdp_command:= my_c_bdp_connection.CreateCommand;
nous remplissons la requête par: my_c_bdp_command.CommandText:= 'CREATE etc';
nous envoyons la requête vers le Serveur par: my_c_bdp_command.ExecuteNonQuery;
Nous pouvons aussi ajouter des transactions pour encadrer cette création.
Donc: créez une nouvelle application Windows Forms et appelez-la "p_ib_bdp_create_table" posez un Button, appelez-le "create_", créez son événement OnClick et tapez les instructions de création de table: const k_database_file= '..\_data\INSTITUT_PASCAL_5.GDB'; k_table_name= 'formations_5'; k_connection_string= 'assembly=Borland.Data.Interbase, Version=1.5.0.0, ' + 'Culture=neutral,PublicKeyToken=91d62ebb5b0d1b1b;vendorclient=gds32.dll ;' + 'database='+ k_database_file+ ';' + 'provider=Interbase;username=sysdba;password=masterkey'; k_sql_create= 'CREATE TABLE '+ k_table_name + ' (f_id INTEGER, f_name CHAR(28), f_days INTEGER, f_price DOUBLE P RECISION )'; procedure TWinForm.create_transaction__Click(sender: System.Object; e: System.E ventArgs); var l_c_bdp_connection: BdpCOnnection; l_c_bdp_transaction: BdpTransaction; l_c_bdp_command: BdpCommand; begin try try l_c_bdp_connection:= BdpConnection.Create(k_connection_string); Include(l_c_bdp_connection.StateChange, BdpConnection1_StateChange); l_c_bdp_connection.Open;
l_c_bdp_transaction:= l_c_bdp_connection.BeginTransaction; l_c_bdp_command:= l_c_bdp_connection.CreateCommand; l_c_bdp_command.CommandText:= k_sql_create; l_c_bdp_command.Connection:= l_c_bdp_connection; l_c_bdp_command.Transaction:= l_c_bdp_transaction; l_c_bdp_command.ExecuteNonQuery; finally l_c_bdp_transaction.Commit; l_c_bdp_connection.Close; end; except on e:exception do begin l_c_bdp_transaction.RollBack; display_bug_stop(e.Message); end; end; // try ... except end; // create_transaction__Click compilez, exécutez, et cliquez le bouton
Dans la foulée, nous pouvons effacer la même table avec la requête Sql suivante: DROP TABLE formations_5
Donc: placez un autre tButton sur la Forme, nommez-le "drop_table" et placez-y la requête de suppression: const k_sql_drop= 'DROP TABLE '+ k_table_name; procedure TWinForm.drop_transaction__Click(sender: System.Object; e: System.Ev entArgs); var l_c_bdp_connection: BdpCOnnection; l_c_bdp_transaction: BdpTransaction; l_c_bdp_command: BdpCommand; begin try try l_c_bdp_connection:= BdpConnection.Create(k_connection_string); Include(l_c_bdp_connection.StateChange, BdpConnection1_StateChange);
l_c_bdp_connection.Open; l_c_bdp_transaction:= l_c_bdp_connection.BeginTransaction; l_c_bdp_command:= l_c_bdp_connection.CreateCommand; l_c_bdp_command.CommandText:= k_sql_drop; l_c_bdp_command.Connection:= l_c_bdp_connection; l_c_bdp_command.Transaction:= l_c_bdp_transaction; l_c_bdp_command.ExecuteNonQuery; finally l_c_bdp_transaction.Commit; l_c_bdp_connection.Close; end; except on e:exception do begin l_c_bdp_transaction.RollBack; display_bug_stop(e.Message); end; end; // try ... except end; // drop_transaction__Click
compilez, exécutez, et cliquez le bouton
Vous pouvez télécharger le sources du projet "win_bdp_create_table.zip".
4.2 - Vérifier la création Nous pouvons vérifier que la création a été effectuée en utilisant la fonction GetMetaData de BdpConnection. La technique est similaire à celle utilisée partSession.GetTableNames du temps de l'antique BDE. Dans notre cas: créez une nouvelle application en cliquant "Fichiers | Nouveau | Windows Forms" et renommez-la "p_win_bdp_metadata" posez une ListBox sur la Forme posez un Button, nommez-le "table_", créez son événement OnClick qui va afficher
dans ListBox1 le nom des tables: procedure TWinForm.tables_Click(sender: System.Object; e: System.EventArgs); var l_c_bdp_connection: BdpCOnnection; l_c_data_table: DataTable; l_table_index: integer; begin try Datagrid1.DataSource:= nil; l_c_bdp_connection:= BdpConnection.Create(k_connection_string); Include(l_c_bdp_connection.StateChange, BdpConnection1_StateChange); l_c_bdp_connection.Open; try l_c_data_table:= l_c_bdp_connection.GetMetaData.GetTables('', Borland.Data.Schema.TableType.Table); DataGrid1.DataSource:= l_c_data_table; ListBox2.Items.Clear; for l_table_index:=0 to l_c_data_table.Rows.Count-1 do ListBox2.Items.Add(l_c_data_table.Rows[l_table_index].Item['TableName']); finally l_c_bdp_connection.Close; end; except on e:exception do DataGrid1.CaptionText:= e.Message; end; // try ... except end; // tables_Click posez un DataGrid sur la Forme sélectionnez ListBox1, créez son événement MouseDown et affichez le contenu de la table sélectionnée: procedure TWinForm.ListBox2_MouseDown(sender: System.Object; e: System.Wind ows.Forms.MouseEventArgs); var l_c_bdp_connection: BdpCOnnection; l_c_data_table: DataTable; l_table_name: String; begin try Datagrid1.DataSource:= nil; Text:= k_database_file; l_c_bdp_connection:= BdpConnection.Create(k_connection_string); Include(l_c_bdp_connection.StateChange, BdpConnection1_StateChange); l_c_bdp_connection.Open;
try l_table_name:= ListBox2.Items[ListBox2.SelectedIndex].ToString; l_c_data_table:= l_c_bdp_connection.GetMetaData.GetColumns(l_table_name, '', Borland.Data.Schema.ColumnType.Unknown); DataGrid1.DataSource:= l_c_data_table; finally l_c_bdp_connection.Close; end; except on e:exception do DataGrid1.CaptionText:=e.Message; end; end; // ListBox2_MouseDown compilez et exécutez. Cliquez "table_" et cliquez "FORMATIONS_5" voici le résultat:
5 - Ajouter des Données Pour ajouter un enregistrement 3, Interbase Delphi l'instruction SQL à exécuter est:
INSERT INTO formations (f_numero, f_nom) VALUES (3, 'Interbase Delphi')
Créons une nouvelle application pour pouvoir ajouter quelques lignes: créez une nouvelle application Windows Forms et appelez-la "p_win_bdp_insert_data" posez un Button, appelez-le "insert_", créez son événement OnClick et tapez les instructions qui inséreront une ligne: const k_sql_insert= 'INSERT INTO '+ k_table_name + ' (f_id, f_name, f_days, f_price)' + ' VALUES (3, ''Delphi Interbase'', 3, 1400)'; procedure TWinForm.insert_Click(sender: System.Object; e: System.EventArgs); var l_c_bdp_connection: BdpCOnnection; l_c_bdp_command: BdpCommand; begin try try l_c_bdp_connection:= BdpConnection.Create(k_connection_string); Include(l_c_bdp_connection.StateChange, BdpConnection1_StateChange); l_c_bdp_connection.Open; l_c_bdp_command:= l_c_bdp_connection.CreateCommand; l_c_bdp_command.CommandText:= k_sql_insert; l_c_bdp_command.ExecuteNonQuery; finally l_c_bdp_connection.Close; end; except on e:exception do display_bug_stop(e.Message); end; // try ... except end; // insert_Click compilez, exécutez, et cliquez le bouton
Nous pouvons automatiser ces ajouts en paramétrant la procédure qui envoie les valeurs littérales. Voici un exemple: posez un Button, appelez-le "insert_several_", créez son événement OnClick et tapez les
instructions qui inséreront plusieurs lignes: procedure TWinForm.insert_several__Click(sender: System.Object; e: System.Event Args); var l_c_bdp_connection: BdpCOnnection; l_c_bdp_command: BdpCommand; procedure insert_generic(p_number: Integer; p_name: String; p_days: Integer; p_price: Double); var l_sql_text: String; begin DecimalSeparator:= '.'; l_sql_text:= 'INSERT INTO '+ k_table_name + ' (f_id, f_name, f_days, f_price)' + ' VALUES ' + ' (' + IntToStr(p_number)+ ', '+ QuotedStr(p_name)+ ', ' + IntToStr(p_days)+ ', '+ FloatToStr(p_price) + ' )'; DecimalSeparator:= ','; display(l_sql_text); l_c_bdp_command.CommandText:= l_sql_text; Try l_c_bdp_command.ExecuteNonQuery; Except on e: Exception do display(' *** pb_insert '+ e.Message); end; end; // insert_generic begin // insert_several__Click try try l_c_bdp_connection:= BdpConnection.Create(k_connection_string); Include(l_c_bdp_connection.StateChange, BdpConnection1_StateChange); l_c_bdp_connection.Open; l_c_bdp_command:= l_c_bdp_connection.CreateCommand; insert_generic(1, 'Initiation Delphi', 3, 1400.40); insert_generic(2, 'Bases de Données Delphi', 3, 1400); insert_generic(3, 'Interbase Delphi', 3, 1400); insert_generic(4, 'Composants Delphi', 3, 1400); insert_generic(5, 'UML et Patterns Delphi', 3, 1400); insert_generic(6, 'Delphi Asp', 3, 1400); finally l_c_bdp_connection.Close;
end; except on e:exception do display_bug_stop(e.Message); end; // try ... except end; // insert_several__Click compilez, exécutez, et cliquez le bouton
6 - Lire et Afficher 6.1 - Affichage par code Nous allons maintenant afficher les données. Une première technique consiste à lire les données en utilisant un DataReader. Plaçons cet affichage dans le projet précédent: posez un Button, appelez-le "select_", créez son événement OnClick et tapez les instructions qui afficheront les lignes dans un TextBox: procedure TWinForm.select__Click(sender: System.Object; e: System.EventArgs); var l_c_bdp_connection: BdpConnection; l_c_bdp_command: BdpCommand; l_c_data_reader: BdpDataReader; l_field_index: Integer; l_line: String; l_formatted_value: String; begin try try l_c_bdp_connection:= BdpConnection.Create(k_connection_string); Include(l_c_bdp_connection.StateChange, BdpConnection1_StateChange); l_c_bdp_connection.Open; l_c_bdp_command:= l_c_bdp_connection.CreateCommand; l_c_bdp_command.CommandText:= k_sql_select; l_c_data_reader:= l_c_bdp_command.ExecuteReader; while l_c_data_reader.Read do begin l_line:= '';
for l_field_index:= 0 to l_c_data_reader.FieldCount- 1 do begin l_formatted_value:= l_c_data_reader.GetValue(l_field_index).ToString; Case l_field_index of 0 : l_formatted_value:= Format('%-3s', [l_formatted_value]); 1 : l_formatted_value:= Format('%-28s', [l_formatted_value]); 2 : l_formatted_value:= Format('%-3s', [l_formatted_value]); 3 : l_formatted_value:= Format('%-6s', [l_formatted_value]); end; // case l_line:= l_line+ l_formatted_value+ '|' end; // for all fields display(l_line); end; // while Read Finally l_c_data_reader.Close; End; // try ... finally Except On e: Exception do display('*** '+ e.Message) end; // try ... except display('< select'); end; // select__Click compilez, exécutez, et cliquez le bouton voici le résultat:
6.2 - Affichage en mode conception Nous allons aussi utiliser des composants posés sur la Forme au lieu d'utiliser la création dynamique par code: créez une nouvelle application Windows Forms et appelez-la "p_win_bdp_select"
connectez le Serveur:
dans la page "Borland Data Provider" sélectionnez un BdpConnection et posez-le sur le Forme sélectionner BdpConnection1, et avec un Click droit souris, ouvrez l'Editeur de Connections o sélectionnez le pilote IbConn1 o tapez le chemin _DATA\INSTITUT_PASCAL_5.GDB o testez la connection en cliquant "Test" o fermez le dialogue de connection en cliquant "OK"
dans la page "Borland Data Provider" sélectionnez un BdpDataAdapter:
et posez-le sur le Forme Définissez la requête de sélection:
sélectionnez le BdpDataAdapter1, cliquez sur le bouton droit, sélectionnez "Configure Data Adapter" le Configurateur de Data Adapter est affiché:
sélectionnez FORMATIONS_5, puis "Generate Sql" le code "SELECT ... " est généré
sélectionnez l'onglet "Preview Data" cliquez "Refresh" les données de la table sont affichés:
pour afficher les données sur la Forme, nous créons un DataSet qui sera rempli par le BdpDataprovider. Pour cela, sélectionnez l'onglet "Dataset" du configurateur, choisissez le bouton "New Data":
Fermez le Configurateur en cliquant "OK"
DataSet1 est automatiquement ajouté aux composants De plus sur disque est apparu DataSet1Unit.pas (19 K, tout de même) avec, semble-t-il, les champs persistents et des événements de gestion des modifications et de traitements .XML
dans l'onglet "Data Controls" sélectionnez un DataGrid:
et posez le sur la Forme. Puis:
sélectionnez sa propriété DataSource et mettez-y DataSet1 sélectionnez sa propriété DataMember et mettez-y FORMATIONS_5
ouvrez le DataAdapter1: sélectionnez sa propriété Active et basculez-la sur True les données sont affichées dans DataGrid1:
7 - Modifier des Données Nous allons à présent mettre en place la modification de données. Commençons par une application qui affiche des données dans un DataGrid: créez une nouvelle application Windows Forms et appelez-la "p_win_bdp_update_data" connectez le Serveur:
dans la page "Borland Data Provider" sélectionnez un BdpConnection et posez-le sur le Forme sélectionner BdpConnection1, et avec un Click droit souris, ouvrez l'Editeur de Connections o sélectionnez le pilote IbConn1 o tapez le chemin _DATA\INSTITUT_PASCAL_5.GDB o testez la connection en cliquant "Test"
o
fermez le dialogue de connection en cliquant "OK"
dans la page "Borland Data Provider" sélectionnez un BdpDataAdapter et posez-le sur le Forme Définissez la requête de sélection:
sélectionnez le BdpDataAdapter1, cliquez sur le bouton droit, sélectionnez "Configure Data Adapter" sélectionnez FORMATIONS_5, toutes ses colonnes, puis "Generate Sql" le code "SELECT ... " est généré sélectionnez l'onglet "Preview Data" cliquez "Refresh" les données de la table sont affichés pour afficher les données sur la Forme, nous créons un DataSet qui sera rempli par le BdpDataprovider. Pour cela, sélectionnez l'onglet "Dataset" du configurateur, choisissez le bouton "New Data". Fermez le Configurateur en cliquant "OK"
DataSet1 est automatiquement ajouté aux composants et DataSet1Unit.pas est généré sur disque
dans l'onglet "Data Controls" sélectionnez un DataGrid et posez le sur la Forme. Puis:
sélectionnez sa propriété DataSource et mettez-y DataSet1 sélectionnez sa propriété DataMember et mettez-y FORMATIONS_5
ouvrez le DataAdapter1: sélectionnez sa propriété Active et basculez-la sur True
A présent la partie de mise à jour: sélectionnez DataAdapter1 et sa propriété UpdateCommand: vous voyez dans sa propriété CommandText la requête Sql suivante: UPDATE FORMATIONS_5 SET F_ID = ?, F_NAME = ?, F_DAYS = ?, F_PRICE = ? WHERE F_ID = ? AND F_NAME = ? AND F_DAYS = ? AND F_PRICE = ? Cette requête a en fait été générée automatiquement lorsque nous avons crée la requête SELECT. Si cette requête ne nous convient pas, nous pourrions la modifier (changer
le WHERE pour retrouver l'ancienne ligne sur la clé uniquement, par exemple) ajoutons l'instruction de mise à jour: posez un Button sur la Forme, nommez-le "update_" et créez son événement OnClick: const k_table_name= 'formations_5'; procedure TWinForm.update__Click(sender: System.Object; e: System.EventArgs); begin if DataSet1.HasChanges then begin BdpDataAdapter1.AutoUpdate(DataSet1, k_table_name, BdpUpdateMode.All, [], []); end; end; // tables_Click compilez, exécutez. Puis
modifiez la ligne "Delphi Asp" en "ASP.NET ET DELPHI", par exemple changez de ligne pour poster cliquez "update_"
fermez et réouvrez: la modification a bien été enregistrée
8 - Evaluation Voici quelques commentaires sur cette première utilisation du BDP
le fonctionnement est nettement plus sympathique qu'avec Ado.Net. Freud dirait que j'aurais pu mettre ce commentaire avant de commencer à utiliser le BPD. Quel que soit mon biais, l'empilement Ado.Net, Com Interoperability Layer, OleDb puis le client Interbase (ou autre) ne peut pas être très efficace par défaut au niveau de l'interface programmeur: o l'Editeur de Connection de BdpConnection ne se souvient pas toujours de la connection courante (il s'ouvre toujours sur Db2Conn1) pour les bugs: o NUMERIC : j'avais au début utilisé le type NUMERIC(5, 2) provenant d'un précédent article pour une raison inconnue, l'affichage via un DataSet ne fonctionnait pas. De plus toute la mécanique que nous avons présenté pour afficher en mode conception n'arrêtait pas de présenter des erreur ("input string not of the correct format") j'ai changé le type réel en DOUBLE PRECISION et tout est rentré dans l'ordre o j'ai aussi eu des misères en essayant d'utiliser une table gérée en Delphi 6 et qui comportait des dates. Par conséquent: il vaut mieux pour le moment s'en tenir aux types Interbase simples o le diagnostic de l'erreur a été plus que laborieux. Heureusement que j'avais display: l'affichage de l'indice du champ traité a débusqué le problème BDP est proche dans sa philosophie de dbExpress, et s'en éloigne par la mise en oeuvre. Ce qui est très proche: o nous retrouvons la chaîne connection (tSqlConnection / BdpConnection) adaptateur (tDataSetProvider / BdpDataAdapter) dataset (tClientDataset / DataSet) puis affichage (tdbGrid / DataGrid) o la modification se fait en appelant Update et des paramètres qui guident le mode de mise a jour o
Et ce qui change: avec le BDP, la relation entre l'adaptateur et le DataSet est initialisée par l'Adaptateur. C'est en fait toute l'architecture des composants de visualisation qui a été généralisée, et ceci explique ce changement de liaison o le DataGrid a 2 propriétés (DataSource ET DataMember) d'une façon plus générale, la masse de code générée par Delphi 8 pour faire fonctionner l'ensemble est à la fois impressionnant et, à mon avis, un peu o
inquiétant: soit cette masse est impérative et c'est un défaut, soit Borland a forcé le comportement très général de Ado.Net pour le façonner au moule Delphi 6 et cela m'incite à voir quel serait le fonctionnement sans tout cela...
Delphi 8 propose aussi un explorateur de données "Voir | Data Explorer":
et en cliquant "Interbase", "IbConn1" et FORMATIONS_5 nous avons bien notre table et ses données:
Cet explorateur est en fait un .EXE autonome. Mais je n'ai pas très bien su l'exploiter:
comment fournir la base à examiner (la chaîne de connection) les changement de l'application Delphi semble sélectionner ou modifier la base utilisée
Extraction de Script SQL - John COLIBRI.
résumé : Comment générer un script SQL à partir d'une base de données Interbase / Firebird mots clé : script SQL - Interbase - Firebird - IbExtract logiciel utilisé : Windows XP personnel, Delphi 6.0 matériel utilisé : Pentium 2.800 Mhz, 512 Meg de mémoire, 250 Giga disque dur champ d'application : Delphi 1 à 2006, Turbo Delphi sur Windows niveau : développeur Delphi - développeur Interbase plan : o Introduction o Principe o Le Projet Delphi o Télécharger le code source Delphi
1 - Introduction
Cet article va indiquer comment extraire d'une base de données existante un script SQL capable de recréer la même base. Cet utilitaire permet:
de sauvegarder de façon lisible (mais verbeuse) les données d'une base de porter facilement les données d'une version d'un même moteur à une autre version d'adapter et modifier les données pour les porter sur un autre moteur, ou changer son fonctionnement (passer du dialecte Interbase 1 au dialecte 3) de changer la structure de la base, ou la valeur des données de documenter la base (en utilisant des outils de génération de documentation à partir du script)
Nous avons utilisé cet utilitaire dans notre article sur MastApp, la base de démonstration de Delphi
2 - Principe Nous pouvons utiliser plusieurs techniques:
analyser les tables système qui contiennent tout les informations sur la base utiliser des composants Delphi qui sont capables d'extraire le schéma utiliser des outils externes tels que IbExpert
Comme Delphi fournit, depuis Delphi 6, un composant spécifique d'extraction de schéma pour Interbase, nous avons opté pour cette technique-là. Notez que si nous souhaitions effectuer une extraction directe à partir des tables système, un moyen commode serait d'examiner le code source d'Ibx et d'adapter ce code pour nos propres besoins. Dans notre cas, le composant IbExtract donne satisfaction, et nous nous contenterons de l'utiliser
3 - Le Projet Delphi 3.1 - L'Objectif Nous devons créer un script qui permettra :
de créer les tables ainsi que toutes leurs annexes (générateurs, triggers etc) de remplir les données des tables
3.2 - Le composant IbExtract Ce composant a été construit uniquement pour extraire les données d'une base. Je suppose que Jeff OVERCASH l'a spécialement créé pour écrire IbConsole. Il devrait donc nécessairement permettre de réaliser notre travail. Le principal problème à résoudre est de trouver les paramètres à utiliser. La documentation indique que
la syntaxe de base est: nous appelons Extract de la façon suivante: type TExtractObjectTypes= (eoDatabase, eoDomain, eoTable, eoView, eoProcedure, eoFunction, eoGenerator, eoException, eoBLOBFilter, eoRole, eoTrigger, eoForeign, eoIndexes, eoChecks, eoData); TExtractType= (etDomain, etTable, etRole, etTrigger, etForeign, etIndex, etData, etGrant, etCheck, etAlterProc); TExtractTypes= Set of TExtractType; procedure ExtractObject(ObjectType: TExtractObjectTypes; ObjectName: String; ExtractTypes: TExtractTypes);
les paramètres sont: o le type de donnée à extraire: eoDomain pour les domaines, eoTable pour les tables etc o si nous ciblons un objet particulier (une table, une procédure cataloguée etc), le nom de cet objet o pour un objet donnée, le dernier paramètre spécifie quelle donnée (par exemple pour une table, le triggers en utilisant etTrigger)
En ce qui nous concerne, nous espérions pouvoir tout extraire (les requêtes de création de tables, les triggers etc et les données) par: IbExtract1.ExtractObject(eoDataBase, '', []);
mais cet appel fournit bien le script de toutes les créations, mais pas le script pour les données.
Après quelques essais, l'appel: IbExtract1.ExtractObject(eoTabke, 'orders', [etData]);
fournit bien le script des données de la table ORDERS, mais aussi au début le script de création de cette table. En combinant les deux appels, nous obtenons finalement notre résultat.
3.3 - Le code d'extraction du schéma Voici le projet: créez une nouvelle application Delphi et renommez-la "p_extract_ib_script" ajoutez un tMemo qui recevra le script du schéma de la page "Interbase" de la Palette, sélectionnez IbTransaction et posez-le sur la Forme de la page "Interbase" de la Palette, sélectionnez IbDataBase et posez-le sur la Forme reliez IbTransaction1 et IbDataBase1 double cliquez sur IbDatabase1 pour afficher l'Editeur de Connection. Remplissez le nom de la base, le nom de l'utilisateur, le mot de passe (SYSDBA), décochez "LoginPrompt":
Cliquez "Ok" pour sauvegarder, double-cliquez à nouveau et sélectionnez "Test" pour vérifier la connection de l'onglet "Interbase" de la Palette sélectionnez IbExtract et posez-le sur la Forme
posez un tButton sur la Forme, renommez-le "complete_schema_", créez son événement OnClick et écrivez le code qui extrait toutes les requêtes de création du schéma: procedure TForm1.complete_schema_Click(Sender: TObject);
begin open_database_Click(Nil); with IBExtract1 do begin ExtractObject(eoDataBase, '', []); Memo1.Lines.Assign(Items); end; end; // complete_schema_Click compilez, exécutez et cliquez "complete_schema_" le schéma complet s'affiche dans Memo1
3.4 - Le code d'extraction des données Pour extraire les données, nous allons procéder en deux étapes:
trouver le nom de toutes les tables pour chaque table, appeler ExtractObject avec le paramètres etData
L'extraction des noms de Table est réalisé en appelant la procédure d'extraction complète ci-dessus, et en extrayant le nom situé après chaque CREATE DATABASE .
Voici comment placer le nom de chaque Table dans une tListBox: ajoutez une tListBox au projet ajoutez un tButton, renommez-le "tables_", et tapez le code qui utilise ExtractObject pour récupérer le script de création et en extrait les noms de tables: procedure TForm1.tables_names_Click(Sender: TObject); var l_item: Integer; l_the_line: String; l_index: Integer; l_table_name: String; begin open_database_Click(Nil); ListBox1.Clear; with IBExtract1 do begin
ExtractObject(eoTable, '', []); with Items do for l_item:= 0 to Count- 1 do begin l_the_line:= Trim(Strings[l_item]); if Pos('CREATE TABLE', l_the_line)= 1 then begin System.Delete(l_the_line, 1, Length('CREATE TABLE')); l_index:= 1; l_table_name:= f_string_extract_non_blank(l_the_line, l_index); ListBox1.Items.Add(l_table_name); end; end; end; end; // tables_names_Click ajoutez un tButton, renommez-le "all_table_data_", et tapez le code qui utilise ExtractObject pour récupérer le script d'insertion de données pour chaque Table: procedure generate_insert_into(p_table_name: String; p_c_strings: tStrings); var l_item_index: Integer; l_the_line: String; begin with Form1, IBExtract1 do begin ExtractObject(eoTable, p_table_name, [etData]); // -- skip the schema with Items do begin l_item_index:= 0; while l_item_index< Count do begin l_the_line:= Strings[l_item_index]; if Pos('INSERT INTO', l_the_line)> 0 then Break else Inc(l_item_index); end; // -- now get the INSERT INTO while l_item_index< Count do begin l_the_line:= Strings[l_item_index]; p_c_strings.Add(l_the_line); Inc(l_item_index); end; // while l_item_index
end; // with Items end; // with IBExtract1 end; // generate_insert_into procedure TForm1.all_table_data_Click(Sender: TObject); var l_item_index: Integer; begin with ListBox1 do for l_item_index:= 0 to Count- 1 do generate_insert_into(Items[l_item_index], Memo1.Lines); end; // all_table_data_Click compilez, exécutez et cliquez "complete_schema_" voici une vue du projet: compilez, exécutez et cliquez "all_table_data_" voici une vue du projet, avec le script pour PARTS:
Fonctions Utilisateur Interbase (UDF) - John COLIBRI.
résumé : Création et utilisation de fonctions utilisateur Interbase en Delphi mots clé : UDF - Interbase - User Defined Function - DLL logiciel utilisé : Windows XP personnel, Delphi 6.0, Interbase 6
matériel utilisé : Pentium 2.800 Mhz, 512 Meg de mémoire, 250 Giga disque dur champ d'application : Delphi 1 à 2006 sur Windows, Interbase niveau : développeur Delphi / Interbase plan : o Les UDF Interbase o Le Projet Delphi o Ajout d'une UDF o Télécharger le code source Delphi
1 - Les UDF Interbase Interbase fut le premier moteur à proposer l'ajout de fonctions externes. Les UDF (User Defined Functions sont des routines placées dans des DLL Windows qui peuvent être utilisées dans des requêtes SQL. Nous nous sommes surtout intéressés aux UDF car la base de donnée du Portail Asp Net Delphi emploie de telles fonctions. Pour pouvoir intégralement recréer le Portail, il faut ajouter les UDF, d'où le présent article.
2 - Ajout d'une UDF 2.1 - Principe des EXTERNAL FUNCTIONS Voici la situation avant l'ajout d'une UDF:
Pour ajouter une UDF, il faut
écrire la DLL qui exporte la routine qui nous intéresse
placer la DLL dans le répertoire des UDF Interbase
ajouter la routine en tant que EXTERNAL FUNCTION aux objets des bases qui souhaitent l'utiliser
utiliser la routine dans nos requêtes SQL
2.2 - La fonction utilisée Nous allons écrire des UDF qui ajouterons à Interbase quelques fonctions de traitement de chaînes de caractères:
RTRIM(p_chaîne) qui supprime les espaces situés après une chaîne STRLEN(p_chaîne) qui retourne la taille d'une chaîne RPAD(p_chaîne, p_taille_max, p_caractère) qui complète une chaîne avec le caractère p_caractère pour arriver à la taille p_taille_max SUBSTR(p_chaîne, p_position, p_nombre) qui extrait de p_nombre caractères à partir de p_position
3 - Le Projet Delphi 3.1 - L'écriture de l'UDF Les fonctions externes doivent être placées dans une .DLL Windows. Cette .DLL peut être réalisée avec n'importe quel outil. En général, n'importe lequel n'est pas assez bon, et c'est pourquoi nous utiliserons Delphi. L'unité qui calcule les chaînes est la suivante:
unit u_udf_string; interface uses SysUtils, Windows, Classes;
function f_trim_right(p_pchar: PChar): PChar; cdecl; export; function f_right_pad(p_pchar: PChar; var pv_target_length: Integer; p_pad_pchar: PChar): PChar; cdecl; export; function f_string_length(p_pchar: PChar): Integer; cdecl; export; function f_sub_string(p_pchar: PChar; VAR pv_position, pv_length: Integer): PChar; cdecl; export; implementation uses u_udf_globals; function f_trim_right(p_pchar: PChar): PChar; begin Result:= f_build_pchar(PChar(TrimRight(String(p_pchar))), nil, 0); end; // f_trim_right function f_right_pad(p_pchar: PChar; var pv_target_length: Integer; p_pad_pchar: PChar): PChar; cdecl; export; // -- complement the string to the right up to the desired length var l_string, l_padded_string: String; l_padded_length, l_length, l_index: Integer; begin l_string:= String(p_pchar); l_length:= Length(l_string); l_padded_string:= String(p_pad_pchar); l_padded_length:= Length(l_padded_string); if (l_length< pv_target_length) and (l_padded_length '2004/05/01' o
de trier le résultat:
SELECT * FROM dates ORDER BY f_date o
Ce qu'il faut bien comprendre est que:
SELECT calcule un résultat A PARTIR de tables, mais que le résultat n'EST PAS les tables. Lorsque nous demandons une somme ou une moyenne, par exemple,SELECT retourne un nombre. Certes, "SELECT * FROM formations" retourne bien les mêmes données que celle de la table sur disque "formations". Mais ce n'est qu'un instantané réalisé lorsque la requête a été lancée. Il s'agit d'une copie. Si un autre utilisateur ajoute une nouvelle formation la copie que nous avons dans le cache attaché à IbQuery ne le reflète pas pour rafraîchir notre cache, la SEULE façon de faire est de relancer la requête (en fermant et réouvrant tIbQuery)
6.6 - Changement de requête Notre exemple présente une lecture dans laquelle l'utilisateur tape sa requête dans un tEdit. Rien de bien particulier, sauf que ceci permet d'explorer facilement une table (sans utiliser l'Explorateur de bases de données).
6.7 - Requête paramétrée Chaque fois que nous souhaitons une information, nous devons exécuter un SELECT. Lorsque la requête est complexe (plusieurs tables, sous-requête, agrégats etc) le Serveur essaye d'optimiser le calcul du résultat. Cette optimisation peut être longue. Si nous devons exécuter la requête plusieurs fois de suite, Sql offre la possibilité de scinder la requête en deux:
envoyer le squelette de la requête contenant des paramètres fournir la valeur des paramètres et demander le résultat
Dans le premier temps, le Serveur calcule sa méthode d'accès, mais n'exécute rien car il lui manque la valeur des paramètres. Lorsque le Serveur reçoit les paramètres, il lance le calcul en utilisant son plan d'évaluation, et retourne le résultat. Et ceci autant de fois que le squelette de la requête ne change pas. Pour effectuer ce travail en deux temps:
nous rédigeons une requête qui contient des paramètres. En Delphi, ces paramètres sont désignés par un identificateur précédé de ":". Par exemple SELECT * FROM dates WHERE f_date= : ma_date
Notez que: o l'identificateur n'a pas besoin d'avoir le même nom que la colonne o les paramètres peuvent seulement apparaître dans la clause WHERE (pas dans les champs ou pour le nom des tables) o ":" et ma_date sont collés (pas d'espace entre les deux) la requête est envoyée vers le Serveur par IbQuery1.Prepare;
lorsque nous souhaitons obtenir un résultat o nous initialisons la valeur des paramètres en utilisant tIbQuery.Params IbQuery1.Params[0].AsString:= '2004/03/01'; o
ou IbQuery1.ParamByName('ma_date').AsString:= Edit3.Text;
o
nous lançons la requête par: IbQuery1.Open;
o
En pratique: créez une nouvelle application et appelez-la "p_ib_parametrized" placez un tIbTransaction sur la Forme placez un tIbDataBase sur la Forme. Cliquez deux fois sur IbDataBase1, renseignez "local", "DataBase", "User Name" "Pass Word" et "Login Prompt". Vérifiez la connection en basculant IbDataBase1.Connected sur True, puis fermez la
connection. Sélectionnez DefaultTransaction et initialisez-la à IbTransaction1 placez un tIbQuery sur la tForme sélectionnez sa propriété DataBaseName et initialisez-la à IbDataBase1 placez un tButton sur la Forme et créez sa méthode OnClick. Placez-y les instructions de préparation: procedure TForm1.prepare_Click(Sender: TObject); begin with IbQuery1 do begin Close; with Sql do begin Clear; Add('SELECT * FROM formations WHERE f_nom= :le_nom'); end; // with Sql Prepare; end; // with IbQuery1 end; // prepare_Click placez un tButton sur la Forme et créez sa méthode OnClick. Placez-y les instructions qui initialisent les paramètres et ouvrent la table: procedure TForm1.close_params_open_Click(Sender: TObject); begin with IbQuery1 do begin // -- close in case has done a previous request Close; // -- set the parameter values with Sql do ParamByName('le_nom').AsString:= parameter_edit_.Text; // -- send the parameter to the database Open; end; // with IbQuery1 end; // close_params_open_Click compilez, exécutez, et cliquez le bouton qui lance la requête
Vous pouvez télécharger le source du projet "ib_parametrized.zip".
7 - Modifier des Données 7.1 - Principe Supposons que notre table FORMATIONS contienne les valeurs suivantes:
Pour changer le libellé "Interbase Delphi" en "Interbase" nous utilisons une requête UPDATE: UPDATE formations SET f_nom= 'Interbase' WHERE f_numero= 8
Cette requête qui modifie les données du Serveur est envoyée vers le Serveur en utilisant tIbQuery1.ExecSql
En détail: créez une nouvelle application "p_update_data" placez un tIbTransaction sur la Forme placez un tIbDataBase sur la Forme. Cliquez deux fois sur IbDataBase1, renseignez "local", "DataBase", "User Name" "Pass Word" et "Login Prompt". Vérifiez la connection en basculant IbDataBase1.Connected sur True, puis fermez la connection. Sélectionnez DefaultTransaction et initialisez-la à IbTransaction1 placez un tIbQuery sur la tForme sélectionnez sa propriété DataBaseName et initialisez-la à IbDataBase1 placez un tButton sur la Forme et créez sa méthode OnClick. Placez-y les instructions de modification: procedure TForm1.Button1Click(Sender: TObject); begin
with IbQuery1 do begin Close; with Sql do begin Clear; Add('UPDATE formations SET f_nom=''Interbase'' where f_numero= 3'); end; // with Sql Try ExecSql; except on e:exception do display(' *** pb_update'+ e.Message ); end; // Try...Except end; // with IbQuery1 end; // Button1Click compilez, exécutez, et cliquez le bouton
Vous pouvez télécharge le source du projet ib_update_data.zip".
7.2 - La clause WHERE Dans l'instruction précédente nous avons spécifié la valeur f_numero à l'aide de WHERE. Que se passerait-il si nous envoyons: UPDATE formations SET f_nom= 'Interbase'
Eh bien le Serveur modifierait le nom de TOUS les enregistrements. Si nous souhaitons limiter les modifications à certaines lignes, il est impératif:
que chaque ligne de chaque table ait un identificateur unique pour que nous puissions désigner cette ligne en cas de modification que nous indiquions dans UPDATE les lignes à modifier
Si en revanche nous souhaitons modifier plusieurs lignes à la fois, nous pouvons :
omettre WHERE. Par exemple, pour passer tous les noms en majuscule: UPDATE formations SET f_nom= UPPER(f_nom)
changer plusieurs lignes satisfaisant une condition. Pour effectuer une réduction promotionnelle de 5% sur les prix inférieurs à 1400 euros : UPDATE formations SET f_prix= f_prix* 0.95 WHERE WHERE f_prix
View more...
Comments