• Aucun résultat trouvé

Accès aux sources de données géolocalisées

3.3 La correspondance objet-relationnel

3.3.3 Connexion à la base de données

Un serveur de bases de données peut être exécuté localement en mode "standalone" ou sur une autre machine. Dans les deux cas, il est chargé de la gestion des fichiers de stockage et effectue des opérations pour le compte de chaque client.

Pour utiliser la base de données, un client ouvre une connexion avec le serveur, et envoie des commandes à travers une session. Au sein de chaque session, des unités de travail son exécutées.

Une connexion au serveur est créée avec deux objets : le "DatabaseAccessor" et le "Login". Le premier fournit un mécanisme indépendant pour se connecter et se déconnecter du serveur et le second contient les paramètres spécifiques à la connexion tels que le nom d’utilisateur, le mot de passe, et l’environnement.

Création d’un objet connexion La connexion est gérée par la classe "DatabaseAcces-sor" qui requiert un objet "Login" comme paramètre. Cet objet, créé une fois pendant la configuration, est sauvegardé dans une variable partagée et utilisé lors de l’établissement de la connexion.

Le code qui suit montre comment créer un objet "Login" pour une base Postgres sur la machine opale, avec "toto" comme nom d’utilisateur et "passer" comme mot de passe :

login := Login new database: PostgreSQLPlatform new; username: ’toto’; password: ’passer’;

L’objet "Login" contient toutes les informations relatives aux connexion et décon-nexion à une base de données. La variable d’instance "secure" renseignée à ’true" permet à cet objet de garder les paramètres après une connexion réussie.

aLogin secure: true.

Création de l’interface "DatabaseAccessor" L’objet "DatabaseAccessor" fournit une interface abstraite, indépendante des bases de données. Ses instances sont utilisées comme des objets de connexion. Une fois l’objet "Login" crée, une instance de la sous-classe de "DatabaseAccessor" est définie comme suit :

accessor := DatabaseAccessor forLogin: login.

Pour envoyer les commandes par le biais d’un "accessor" de base de données, un objet "session" sera utilisé. Généralement, chaque objet "accessor" appartient à un seul objet "session".

Connexion à la base de données La connexion à une base de données se fait en

utilisant un "accessor" spécifique :

accessor login.

La déconnexion utilise le bout de code suivant :

accessor logout.

Test d’une connexion Après une connexion, il est utile de procéder à des tests pour voir si la connexion est bien établie, le bout de code qui suit permet de faire cela :

[accessor login; logout] on: Error

do: [:ex | Transcript show: ex messageText].

Si "l’accessor" ne peut pas accéder à la base de données, à cause de paramètres incorrects passés à l’objet connexion, par exemple, une exception est levée.

Exécution de requêtes SQL L’objet "DatabaseAccessor" permet aussi d’exécuter directement des requêtes SQL sur une base de données. Ce n’est pas recommandé, mais toutefois, dans certaines situations, il peut être utile.

Pour exécuter un String contenant une expression SQL :

accessor beginTransaction.

3.3. La correspondance objet-relationnel 51

L’objet "result" est un tableau de valeurs représentant les lignes retournées, si elles existent.

Si le String passé à "#executeSQLString :" contient du SQL invalide, une exception est levée. Le bout de code qui suit permet de gérer les exceptions.

[result := accessor executeSQLString: aSQLString] on: Error do: errorBlock

La connexion au serveur de bases de données nécessite une session qui est chargée de coordonner les interactions entre les applications et la base de données.

Création des objets "session" et "Login" Un objet "session" s’occupe de la gestion des requêtes, du cache d’objets, des descripteurs et des unités de travail.

À la fin d’une unité de travail, l’objet "session" décide de l’insertion, de la mise à jour ou de la suppression de données dans la base. Il est également chargé de générer des expressions SQL appropriées pour compléter les unités de travail.

L’objet "Login" contient un objet "DatabaseAccessor" et une instance de la classe "DescriptorSystem" de l’application. Ces paramètres doivent être définis lors de la création de cet objet.

session := MyDescriptorSystem sessionForLogin: aLogin

Un objet "session" est obtenu en utilisant les objets "sessionForLogin :" et "Login". Alternativement, l’objet "session" peut être créé explicitement avec les objets "Login" et "DatabaseAccessor", et la classe "DescriptorSystem".

session := GlorpSession new.

session system: (MyDescriptorSystem forPlatform: myLogin database). session accessor: accessor.

En définissant le "DescriptorSystem" avec l’objet "system :", la session fait une copie du temps d’exécution pour une utilisation pendant la session. Des modifications du comportement de la classe "DescriptorSystem" n’interfèrent pas les sessions actives. Pour cela, un nouvel objet session doit être créé.

"Glorp" peut être utilisé pour modéliser un ensemble de tables d’une base de données relationnelle ou en créer de nouvelles. Dans les deux cas, la classe "DescriptorSystem" est utilisée.

3.3.4 Modélisation d’une base de données avec "Glorp"

La classe "DescriptorSystem" contient des métadonnées pour faire correspondre les objets du modèle aux tables de la base de données. Typiquement, le modèle de l’appli-cation requiert une seule classe "DescriptorSystem". Mais, plusieurs classes peuvent exister dans le modèle, toutes modélisées en utilisant un "DescriptorSystem" unique. C’est à dire, toutes les métadonnées sont encapsulées dans cette classe.

La classe "DescriptorSystem" fournit un comportement qui spécifie les noms de toutes les tables dans le modèle, les classes auxquelles ils correspondent, la structure de chaque table, et les variables d’instance à laquelle ils sont mappés. Ce comportement se traduit par l’ajout de méthodes d’instance qui spécifient toutes les correspondances.

La modélisation d’une base de données nécessite les tâches suivantes : 1. Créer une classe "DescriptorSystem" ;

2. Ajouter des méthodes pour modéliser les tables de la base de données ; 3. Ajouter des méthodes pour construire des descripteurs ;

4. Ajouter des méthodes pour construire des modèles de classe.

Il faut noter qu’avec "Active Record", les deux premiers points suffisent pour faire persister un modèle "Smalltalk" dans une base de données.

Méthodes de création de classes Les objets convertis par "Glorp" en tables, sont représentés en utilisant des classes. Par exemple, les instances d’une classe nommée Ma-Classe peuvent être converties en lignes dans une table nommée MaTable. Généralement, les colonnes de la base de données correspondent à des variables d’instance dans une classe. Si la table comporte une colonne utilisée comme clé primaire, cette dernière doit être considérée également comme une variable d’instance.

Convention de nommage de "Glorp" "Glorp" respecte les conventions de nommage des systèmes de gestion de bases de données relationnelles, mais en propose également d’autres. Par exemple, les noms des tables et colonnes sont écrits en minuscules, avec des mots séparés par des "underscores" alors qu’en "Smalltalk", la plupart des noms utilisent la casse de chameaux "camel case" et les "underscores" ne sont pas recommandés. La casse de chameau est une pratique qui consiste à écrire un ensemble de mots en mettant en majuscule la première lettre des mots liés.

"Glorp" supporte ces deux conventions, mais avec deux exigences, d’abord que les noms des table et colonne commencent par une lettre. Les noms peuvent utiliser toute combinaison de caractères alphanumériques et de soulignement à la suite de cette lettre, mais, ils ne peuvent pas commencer par un "underscore".

Aussi il exige que les noms utilisent le même nom que la table à laquelle ils sont appliqués, annexé avec un suffixe particulier. Par exemple, pour une table appelée "Table" une clé primaire appliquée à une colonne serait appelée "Table_PK".

Création d’un "DescriptorSystem" Avec "Glorp", une application est modélisée en utilisant une sous-classe de "DescriptorSystem". Ce dernier contient tous les descripteurs du modèle (le schéma) en utilisant un certain nombre de méthodes d’instance secondaires.

Le comportement de "DescriptorSystem" définit les classes du modèle et précise les tables de la base de données auxquelles elles doivent être "mappées". Les classes du modèle et les tables correspondant dans la base de données sont représentées par des méthodes distinctes de la classe "DescriptorSystem". Cette classe unique, contient