Couche d'accès aux données simplifiée

Soyez le premier à donner votre avis sur cette source.

Vue 14 644 fois - Téléchargée 1 093 fois

Description

Un jour où j'avais un peu de temps libre, je me suis dis, "Et si je réinventais la roue ?". Appliqué dans ce cas, je me suis demandé comment pourrais-je faire pour créer une librairie d'accès aux données qui soit complètement objet, et qui permette de s'affranchir au maximum du type de SGBD sous-jacent...

Voici le résultat de mon travail.

Le moteur se compose de plusieurs classes :
- Une classe de base pour les données (sérialisable, avec INotifyPropertyChanged)
- Une classe pour implémenter les fonctions minimales requises pour accéder à un SGBD
- Une classe qui permet de faire les requêtes dans la base (insert, update, delete, select)
- Des classes pour définir ces requêtes

Pour définir une donnée (ou entité), on crée une classe qui hérite de ClsBusinessEntity. Elle possède un attribut BusinessTable pour définir à quel table elle appartient. Chacune de ses propriétés possède un attribut BusinessField pour définir le champ de la table (nom du champ, type de donnée, longueur). Si le champ est une clé primaire, on ajoute l'attribut BusinessKeyField. Si c'est un Guid, on met l'attribut BusinessGUID (le traitement est légèrement différent).

Pour accéder à la base de données, on instancie une classe d'accès aux données, qui implémente ClsBusinessDataLayer<TProvider>, qui elle-même utilise Ado.net pour faire la liaison.

Pour utiliser les données, on doit créer un "moteur" pour y accéder. On instancie un ClsBusinessEngine<TEntity, TLayer> où TEntity est le type de l'entité à gérer et TLayer le type de la couche d'accès aux données (ClsBusinessDataLayer).

Après, tout se fait tout seul (ou presque), un petit exemple est fourni, avec une implémentation pour MySql.

Source / Exemple :


using System;
using System.Collections.Generic;
using System.Text;
using System.Data;

namespace MaitreDede.DataAccess.Example
{
    /*

  • CREATE TABLE table_test (
  • id VARCHAR(36) NOT NULL PRIMARY KEY COMMENT '[GUID]',
  • nom VARCHAR(255) NOT NULL
  • );
  • /
[BusinessTable("table_test")] [Serializable] public sealed class ClsTest:ClsBusinessEntity { private Guid _id; private string _nom; [BusinessField("id",DbType.Guid,36)] [BusinessGUID] [BusinessKeyField] public Guid Id { get { return this._id; } set { this._id = value; base.Changed(); } } [BusinessField("nom",DbType.StringFixedLength,255)] public string Nom { get { return this._nom; } set { this._nom = value; base.Changed(); } } } class Program { static void Main(string[] args) { string connectionString = "host=localhost;user=test;password=test;base=test"; //Création de la couche d'accès aux données ClsBusinessDataLayerMysql layer = new ClsBusinessDataLayerMysql(connectionString); //Création du wrapper pour les ClsTest ClsBusinessEngine<ClsTest, ClsBusinessDataLayerMysql> testWrapper = new ClsBusinessEngine<ClsTest, ClsBusinessDataLayerMysql>(layer); //Création de quelques classes de données ClsTest tst1 = new ClsTest(); tst1.Id = Guid.NewGuid(); tst1.Nom = "Test1"; ClsTest tst2 = new ClsTest(); tst2.Id = Guid.NewGuid(); tst2.Nom = "Test2"; //Insertion des données testWrapper.Insert(tst1); testWrapper.Insert(tst2); //Création d'une requête : je sélectionne toutes les ClsTest qui ont un nom égal à 'Test2' //On récupère la définition du champ via le nom de la propriété ClsBusinessFieldDefinition defChampNom = testWrapper["Nom"]; //Création de l'opérande "champ de table" ClsOperandField champNom = new ClsOperandField(defChampNom); //Création de l'opérande "paramètre" (pour ajouter des constantes à la requête) ClsOperandParameter valeurChamp = new ClsOperandParameter(defChampNom, "Test2"); //Création de la clause complète ClsBusinessQueryOperation clause = new ClsBusinessQueryOperation(ClsOps.Equal, champNom, valeurChamp); //Au final, on a fait une condition : table_test.nom = 'Test2' //On sélectionne les données selon ce filtre ClsBusinessDataReader<ClsTest> dataReader = testWrapper.Select(clause); //On lit le datareader while (dataReader.Read()) { //On récupère la ligne courante ClsTest entity = dataReader.GetEntity(); //On en fait ce qu'on veux Console.WriteLine("id:" + entity.Id + " nom:" + entity.Nom); } dataReader.Close(); } } }

Conclusion :


Ma librairie offre beaucoup de possibilités, tant qu'on n'utilise pas de trucs trop "tordus".

Je l'ai implémenté pour MySql (fourni), mais aussi pour OleDb et SqlServer.

J'ai aussi fait une appli qui utilise cette librairie, et où la personne qui configure l'application peut choisir sur quelle base de données l'application doit tourner.

Codes Sources

A voir également

Ajouter un commentaire Commentaires
Messages postés
458
Date d'inscription
dimanche 22 décembre 2002
Statut
Membre
Dernière intervention
18 avril 2009

Elle ne se rempli automatiquement que si le champs est marqué comme tel ("Autoincrement")
Messages postés
13
Date d'inscription
vendredi 17 février 2006
Statut
Membre
Dernière intervention
30 avril 2008

salut
j'ai un problème avec les DBNULL dans un datagridview
en fait j'ai ajouter une table dans ma base de données SQL Server2000 et je l'ai lié à un datagrid view, kon j'ajoute une nouvelle ligne par AddNew du binding source la cellule du ID ne se rempli pa alors k dans d'otre table elle se rempli

sauvez moi SVP
Messages postés
153
Date d'inscription
vendredi 9 août 2002
Statut
Membre
Dernière intervention
18 septembre 2009

@Tmcuh : Merci pour ton soutient :)

L'idée de créer la classe teste en dynamique est presque possible, une classe non documentée est ClsBusinessCodeGenerator, qui permet de créer le code des classes à partir de la structure des tables. Elle n'est pas encore parfaite, mais elle existe.

Après, je peux partir autrement (dictionnaire champ/valeur) mais pour l'instant, je n'en ai pas l'utilité. Si des personnes me le demande, je l'implémenterai.

Amicalement,
Dédé
Messages postés
458
Date d'inscription
dimanche 22 décembre 2002
Statut
Membre
Dernière intervention
18 avril 2009

J'oublié la note ^^
Messages postés
458
Date d'inscription
dimanche 22 décembre 2002
Statut
Membre
Dernière intervention
18 avril 2009

Idée original et bien développé, enfin pour le code que tu propose en exemple :) ... j'ai pas encore testé le projet, mais je met 10 pour l'initiative.
Il aurait été simpa de crée la class "ClsTest" de façon entièrement dynamique ce qui permettrait d'avoir un VRAI objet complètement autonome quelque soit la situation et avoir ainsi une dll qui se charge de "tout" pour l'accès au données et renseignement des champs, tables, type, etc.

amicalement,
Tmcuh

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.