Bewise

Nous développons... votre avance

Un exemple d’utilisation du Pattern « Abstract Factory » pour gérer l’aspect multi bases d’un projet Web

SLF
SWA
04/10/2004 - Frédéric Colin
Télécharger la version Word
Télécharger les sources

1 Introduction

L’objectif de cet article est de présenter un exemple d’architecture pour gérer les aspects multi bases d’une application Web.

On demande souvent aux concepteurs de sites Web (et d’applications .NET en général) de faire en sorte que l’applicatif puisse être multi bases tout en offrant la possibilité d’ajouter de nouveaux SGBD par la suite. Cette contrainte majeure peut toutefois être solutionnée en utilisant le modèle (pattern) « Abstract Factory » et la réflexion .NET.

Dans cet article, je fais complète abstraction d’un point important, à savoir les différences fonctionnelles qui peuvent exister entre les différents SGBD au niveau SQL. En effet, je me contente de présenter une solution architecturale pour appréhender les problématiques multi bases.

En tout état de cause, l’état de l’art à ce sujet propose que les procédures stockées (ou procédures cataloguées, ou tout autre nom) soient les plus inintelligentes possibles et ne contiennent aucune règle métier ; en d’autres termes, que du SQL basique. La conséquence directe est que, lors de la création de procédures stockées pour un SGBD cible donné, il faudra vous assurer de l’existence de toute fonctionnalité spécifique que vous utilisez sur l’ensemble des SGBD cibles (paramètres par défaut, boucles, curseurs, etc.).

Cependant, débat concernant le stockage des règles métier dans, soit une couche composant, soit très proche du SGBD, partage les personnes ! L’arrivée de Yukon (SQL Server 2005) relance le débat à ce sujet, en offrant la possibilité de créer des procédures stockées en C# ou en VB.NET… Mais c’est une autre histoire et tel n’est pas le sujet de cet article.

L’exemple proposé a été développé sur la base du Framework 1.1, avec Visual Studio .NET 2003. Une fois n’est pas coutume, l’exemple proposé est à la fois en VB.NET et en VC#.NET.

2 Un peu de théorie

Le pattern « Abstract Factory » est parfaitement adapté aux aspects multi-bases d’une application .NET. Il permet notamment de définir une classe spécifique pour créer l’instance de la classe chargée de l’accès aux données. Il s’agit en quelque sorte d’une usine chargée de la création de la bonne instance de la classe d’accès aux données par un paramétrage quelconque (fichier de configuration .NET et réflexion par exemple).

Voici le schéma de classe global correspondant :

image

· La « classe abstraite d’accès aux données » permet

o de définir les services minimums que devront rendre les composants d’accès aux données qui hériteront de cette classe,

o d’implémenter un certain nombre de méthodes en utilisant les différentes interfaces définies par l’espace de nom « System.Data » (IDbConnection, «IDataReader», etc…).

· Les différentes classes héritant de « Classe Abstraite d’accès aux données » implémentent les méthodes qui doivent l’être afin de gérer au mieux l’accès aux données au SGBD correspondant. Par exemple, pour le cas de SQL Server 2K, la classe correspondante utilisera les classes et méthodes définies dans l’espace de nommage « System.Data.SqlClient ». Ces classes implémenteront les méthodes devant être forcément redéfinies (car déclarées comme telles dans la classe de base) et ne pourront être que des membres d’instance et non des membres partagés du fait de l’impossibilité de

o Définir un membre « MustOverride » et « Shared » en VB.NET

o Définir un membre « Abstract » et « Static » en VC#.NET

· La « classe créatrice d’instance » est une classe aux membres partagés et se charge de la création de la bonne instance de la classe d’accès aux données. Une seule instance sera utilisée pour le reste de l’application une fois que cette usine aura joué son rôle.

A partir de ce moment, tout « l’art » consiste à définir l’ensemble des services qui seront utiles à notre application. Les services de base minimum devront permettre au minimum :

· De paramétrer la chaîne de connexion globalement pour toutes les requêtes ou spécifiquement à une requête,

· De renvoyer des «IDataReader» à partir d’ordres SQL passés en paramètres ou à partir de procédures stockées,

· De remplir des Dataset à partir d’ordres SQL passés en paramètres ou à partir de procédures stockées,

· D’exécuter des requêtes actions à partir d’ordres SQL passés en paramètres ou à partir de procédures stockées,

· D’exécuter des requêtes transactionnelles.

Bref, autant de services qui nécessitent une bonne réflexion en amont de votre projet, dans l’objectif d’une réutilisation maximale de cette assembly d’accès aux données.

Je vous propose de passer maintenant à mon exemple, qui n’implémentera qu’une seule méthode renvoyant un « »IDataReader» », à la fois pour des raisons de simplifications de l’exemple pour illustrer au mieux le pattern, mais aussi pour des questions de temps, je l’avoue.

3 L’exemple par le code

L’exemple que je me propose de développer est simple. Il s’agit de fournir une méthode permettant de renvoyer un «IDataReader» issu de l’exécution d’une procédure stockée éventuellement paramétrée.

La solution .NET proposée est découpée 3 deux projets :

· « Bewise.AbstractFactory » (VB.NET)

· « Bewise.AbstractFactory » (VC#.NET)

· « TestAbstractFactory » (paramétrée pour le projet VC#.NET)

3.1 La base de données

Quel que soit le SGBD utilisé dans l’exemple, SQL Server, Access ou MySQL, la même table est utilisée (issue de la base exemple « Northwind » fournie par Microsoft et recréée pour MySQL) avec la même procédure stockée.

Voici la structure de cette table :

clip_image003

La procédure stockée s’appelle « sSelectCategories ». Cette dernière admet un paramètre optionnel permettant éventuellement de filtrer sur un « CategoryID » donné. Elle sera implémentée sur chacun des SGBD cibles.

Voici la version pour SQL Server :

CREATE PROCEDURE dbo.sSelectCategories ( @CategoryID INT = NULL ) AS BEGIN SELECT Categories.* FROM Categories WHERE ( (@CategoryID IS NULL) OR (CategoryID = @CategoryID) ) END

Voici la version pour Access 2003 :

PARAMETERS [@CategoryID] Long = NULL; SELECT Categories.* FROM Categories WHERE ( ([@CategoryID] IS NULL) OR ((Categories.CategoryID)=[@CategoryID]) );

Voici la version pour MySQL 5.0.1-alpha :

CREATE PROCEDURE sSelectCategories (IN CategID INT) LANGUAGE SQL SQL SECURITY DEFINER BEGIN SELECT * FROM Categories WHERE ( (CategID IS NULL) OR (CategoryID = CategID) ); END

3.2 Le projet « Bewise.AbstractFactory »

Il s’agit de la DLL contenant l’ensemble des classes permettant l’accès aux différents SGBD.

Ce projet contient aussi 4 classes d’accès aux données :

· Une pour SQL Server via son fournisseur géré,

· Une pour un provider OLEDB,

· Une pour Access via le provider OLEDB,

· Une pour MySQL 5.0.1- alpha NT via le managed provider développé par CoreLab http://www.crlab.com et dont Bewise a acquis la version professionnelle 2.50 lors d’un projet récent. Cette assembly est fournie pour cet exemple. A noter que toute utilisation de l’assembly fournie par CoreLab en dehors de cet exemple n’est pas autorisée.

Chacune de ces classes se contente de fournir la méthode définie dans la classe de base et permettant de renvoyer un «IDataReader».

Voici le diagramme de classe associé au projet « Bewise.AbstractFactory » :

clip_image005

Les 4 exemples de classes d’accès aux données fournis présentent une méthode acceptant notamment en paramètre le nom de la procédure stockée à exécuter et éventuellement un ParamArray (VB.NET) ou params (VC#.NET) des valeurs passées en paramètres. Cette façon de faire est rendue possible par une classe spécifique en fonction de l’espace de nom correspondant :

· SqlClient : SqlCommandBuilder

· OleDbClient : OleCommandBuilder

· MySql : MySqlCommandBuilder

Ces classes proposent toutes une méthode « DeriveParameters » qui, à partir d’un objet commande, d’une connexion et du nom d’une procédure stockée, permet de remplir la collection des paramètres de l’objet commande. Bien entendu, cette méthode n’est pas très performante dans la mesure où chaque appel pour exécuter une procédure stockée nécessite 2 appels à la base : l’un pour le remplissage de la collection des paramètres, l’autre pour l’exécution de la procédure stockée. Dans ce cas, la solution consiste à mettre en place un cache contenant la collection des paramètres, afin qu’il n’y ait qu’un seul accès base à la deuxième exécution.

Par contre, vous noterez qu’aucune classe abstraite « CommandBuilder » n’existe pour ces classes. Cela signifie que son implémentation est laissée au bon vouloir du concepteur du namespace d’accès aux données. Par exemple, elle est présente pour l’espace de nom « MySqlClient », mais n’est pas réellement implémentée (déclenchement d’une exception lorsque l’on regarde le code C#). Nous voyons bien que le fait qu’elle soit présente ne signifie en rien que la fonctionnalité sera réellement présente. En effet, prenons aussi le cas de l’espace de nommage « OleDb » : tous les providers OleDb n’implémentent pas forcément cette fonctionnalité. C’est le cas pour le provider de Microsoft Access. D’où l’apparition d’une classe spécifique pour gérer access dans mon exemple.

La classe « DataAccessMaker » présente un membre public partagé qui est chargé au premier appel avec l’instance de la bonne classe d’accès aux données en fonction d’un paramétrage défini dans le fichier de configuration de l’application.

3.3 Le projet « TestAbstractFactory »

Il s’agit du site Web de test référençant le projet DLL et permettant :

· de paramétrer le type de SGBD via un fichier de configuration,

· de récupérer le « IDataReader »,

· d’afficher une grille de données.

Ce projet Web contient un fichier de configuration permettant de définir le mode de fonctionnement de l’accès aux données. Ce dernier contient une balise spécifique appelé « databaseSettings » afin de regrouper ces paramétrages spécifiques :

· DataAccessAssemblyLongFormName : nom long de l’assembly d’accès aux données à charger,

· DataAccessClassName : classe d’accès aux données dont il faudra créer une instance une fois l’assembly chargée en mémoire,

· ConnectionString : chaine de connexion à la source de données.

En voici un exemple :

<databaseSettings> <add key="DataAccessAssemblyLongFormName" value="Bewise.AbstractFactory, Version=0.0.0.1, Culture=neutral, PublicKeyToken=null" /> <add key="DataAccessClassName" value="Bewise.AbstractFactory.AccessDataAccess" /> <add key="ConnectionString" value="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\inetpub\wwwroot\TestAbstractFactory\Northwind2000.mdb;Persist Security Info=False" /> </databaseSettings>

4 Conclusion

Dans cet exemple, je vous ai fait découvrir un exemple d’architecture souple et évolutive permettant de gérer la notion d’accès multi bases d’une application .NET.

Bien entendu, cet exemple est incomplet, mais il a permis de vous montrer une manière de résoudre cette problématique. Il pourrait être amélioré, notamment :

· Lors de la création de l’instance de classe d’accès aux données, vérifier si cette dernière est un sous-type de la classe de base abstraite « DataAccess »,

· Associer un nom fort au projet DLL,

· L’ajout de l’ensemble des fonctionnalités manquantes,

· Gérer les paramètres Output et ReturnValue,

· Gérer le fait qu’une application peut accéder en même temps à plusieurs SGBD et que l’on peut retrouver le même nom de procédure stockée mais avec des paramètres différents (modification à réaliser au niveau des clés de stockage de la HashTable « Parameters »),

· En l’absence du paramétrage, il serait souhaitable de lever une exception technique spécifique pour prévenir le développeur de ce manque, ou bien de définir une classe qui serait instanciée par défaut,

· Il reste à définir si le managed provider utilisé pour MySql dans cet exemple est complet et performant,

· Le chemin physique au fichier Access peut-être calculé en fonction du répertoire virtuel courant.

Remarque : le projet Web est réalisé en VB.NET et fait appel aux deux assemblies VB.NET et VC#.NET implémentant l’exemple. Pour basculer de l’utilisation de l’une à l’autre, suivre les indications dans les fichiers suivants :

· Web.config

· Global.asax

· Webform1.aspx.vb

> Tous les articles

Commentaires

aucun commentaire
Page 1/1
   
Connexion
  • Accueil
  • Plan du site
  • Contact
Bewise TV, Blog technique, Webcasts...

Votre carrière et nous

  • Nos offres
  • Votre candidature
Ignorer les liens de navigation > Accueil > Nos Métiers > Solutions Web Avancées > Détail Article
Ignorer les liens de navigation
Nous
Nos Métiers
Vous Former
Nos Evénements
Nos Références
Nos Activités
Nos Certifications
Nos Chiffres
Le Groupe
Nos Partenaires
On Parle de Nous
Votre Carrière et Nous
Nous Contacter
Défiler vers le haut
Défiler vers le bas
Administration, Système et Communication
Architecture, Méthodes, Industrialisation
Décisionnel et Gestion des Données
Nouvelles Interfaces Utilisateurs
Portail et Travail Collaboratif
Solutions Langages et Framework
Solutions Web Avancées
Défiler vers le haut
Défiler vers le bas
Nos cours
Le Planning
Offres promotionnelles
Défiler vers le haut
Défiler vers le bas
TechDays'12
TechLunch
Windows 8 Camp
Défiler vers le haut
Défiler vers le bas
  • Infos légales
  • Lettre du Regional Director
  • Revue de presse