begin process at 2008 07 21 03:30:55
1 213 565 membres
33 nouveaux aujourd'hui
14 167 membres club

Vous ne trouvez pas de réponse à votre problème ? Alors posez la question dans le forum.
Souvenez-vous qu'il n'y a jamais de question bête, mais rester dans l'ignorance parce que l'on n'ose pas poser une question, ça c'est une erreur !

COUCHE D'ACCÈS AUX DONNÉES SIMPLIFIÉE


Information sur la source

Catégorie :Base de données Source .NET ( DotNet ) Classé sous : données, objet, couche, accès Niveau : Expert Date de création : 04/01/2008 Vu / téléchargé: 3 896 / 255

Note :
10 / 10 - par 1 personne
10,00 / 10

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

Commentaire sur cette source (5)
Ajouter un commentaire et/ou une note


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

  • 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();
  • }
  • }
  • }
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.
Pour les "Membres Club", vous pouvez télécharger directement un fichier contenu dans le zip sans télécharger le zip en entier !

Télécharger le zip

  • signaler à un administrateur
    Commentaire de tmcuh le 04/01/2008 11:51:13

    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

  • signaler à un administrateur
    Commentaire de tmcuh le 04/01/2008 11:51:34 10/10

    J'oublié la note ^^

  • signaler à un administrateur
    Commentaire de maitredede le 04/01/2008 12:02:33

    @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é

  • signaler à un administrateur
    Commentaire de slars le 30/04/2008 14:33:57

    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

  • signaler à un administrateur
    Commentaire de tmcuh le 30/04/2008 14:47:43

    Elle ne se rempli automatiquement que si le champs est marqué comme tel ("Autoincrement")

Ajouter un commentaire

Pub



Appels d'offres

Dessins techniques
Budget : 60€
Animation Flash - Doma...
Budget : 370€
Application flash medi...
Budget : 1 000€

CalendriCode

Juillet 2008
LMMJVSD
 123456
78910111213
14151617181920
21222324252627
28293031   

Téléchargements

Logiciels à télécharger sur le même thème :

Boutique

Boutique de goodies CodeS-SourceS