IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Accès aux données Discussion :

Création d'une classe d'accès aux données


Sujet :

Accès aux données

  1. #1
    Membre à l'essai
    Inscrit en
    Mars 2009
    Messages
    20
    Détails du profil
    Informations forums :
    Inscription : Mars 2009
    Messages : 20
    Points : 11
    Points
    11
    Par défaut Création d'une classe d'accès aux données
    Bonjour,

    Profitant de l'été pour dépoussiérer les connaissances, je suis en train de travailler sur une classe de gestion des accès aux bases de données.

    Les objectifs sont les suivants :

    1. Etre générique autant que possible (utilisation de DbProviderFactory, DbConnection, DbCommand etc.)

    2. Encapsuler et simplifier l'exécution des requêtes, des procédures stockées, la gestion des paramètres

    3. Servir à gérer les accès BDD dans une couche DAO par exemple avec une ou plusieurs bases de données

    La classe DataProvider du tutoriel suivant m'a servi de base :

    http://johannblais.developpez.com/tu...acces-donnees/

    Dans un premier temps, j'utilise comme dans le tutoriel des méthodes statiques afin d'optimiser les performances.

    Le problème, c'est que si je veux utiliser des bases de données différentes dans un projet, j'ai un soucis avec la configuration de la chaîne de connexion.

    En effet, je ne me vois pas changer la chaîne de connexion chaque fois que je veux exécuter une requête.

    J'avais pensé faire une classe de base et faire de l'héritage pour avoir deux classes héritée distinctes avec une chaîne de connexion différente. Malheureusement, vu que les propriétés et méthodes sont statiques, cela ne fonctionne pas...

    Pour l'instant, je sèche et ne vois que deux pistes :

    Changer les méthodes statiques par des méthodes normales et configurer la chaîne de connexion dans le constructeur par exemple, mais cela m'obligera à instancier la classe chaque fois que j'ai besoin de faire un accès à la base de données.

    Ou bien utiliser la solution précédente, mais avec une classe de type singleton pour chaque base de données afin de limiter les créations et destructions d'objets. Seulement, l'utilisation d'un singleton pour gérer les accès aux bases de données semble déconseillé (surtout en ASP.NET), bien que je ne vois pas de différence flagrante au niveau du fonctionnement par rapport aux méthodes statiques...

    Copier comme un porc ma classe actuelle avec ses méthodes statiques me semble contraire à tous les principes de la POO

    Une idée pour résoudre le problème de façon élégante ?
    Ou bien, est-ce que je me prend la tête pour rien, et créer et détruire sans arrêt des objets d'accès aux données comme avec Data Application Block ou Enterprise Library n'est pas si grave en terme de performance ?

    Merci de votre aide

  2. #2
    Membre émérite
    Avatar de laedit
    Homme Profil pro
    Consultant études et développement
    Inscrit en
    Décembre 2006
    Messages
    1 344
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Consultant études et développement
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Décembre 2006
    Messages : 1 344
    Points : 2 265
    Points
    2 265
    Par défaut
    Je pencherais pour la première solution, faire une classe non statique en passant la chaîne de connexion dans le constructeur.

    Il faudra seulement instancié un objet par base de données que tu veux utiliser.

    Ce qui est, somme toute, assez logique.
    Blog - Articles - Framework

    MSDN vous aide, si si, alors n'hésitez pas à y faire un tour avant de poser une question.
    Ah, et n'oubliez pas, Google peut répondre à la majorité de vos questions.

  3. #3
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 749
    Points
    39 749
    Par défaut
    Citation Envoyé par laedit Voir le message
    Je pencherais pour la première solution, faire une classe non statique en passant la chaîne de connexion dans le constructeur
    oui, c'est clairement la meilleure option

    Par contre, si tu veux faire un truc complètement générique, tu vas quand même rencontrer pas mal de problèmes :
    - Tous les SGBD ne supportent pas le même dialecte SQL. Certaines clauses existent sur un SGBD et pas sur un autre (ex. le CONNECT BY d'Oracle), ou encore certaines fonctions sont différentes (NVL sur Oracle, ISNULL sur SQL Server)
    - La syntaxe pour les paramètres de requête n'est pas toujours la même. Certains SGBD utilisent "@nom", d'autres ":nom", certains "?" (pas de nom)... en plus, certains font la liaison des paramètres par nom, d'autres par position...

    Bref... c'est un enfer

    A mon avis, pour pouvoir faire vraiment abstraction du SGBD, il faut utiliser un ORM, genre NHibernate ou Entity Framework

  4. #4
    Membre émérite
    Avatar de laedit
    Homme Profil pro
    Consultant études et développement
    Inscrit en
    Décembre 2006
    Messages
    1 344
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Consultant études et développement
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Décembre 2006
    Messages : 1 344
    Points : 2 265
    Points
    2 265
    Par défaut
    Citation Envoyé par tomlev Voir le message
    A mon avis, pour pouvoir faire vraiment abstraction du SGBD, il faut utiliser un ORM, genre NHibernate ou Entity Framework
    J'approuve, c'est en tout cas le plus facile.

    Sinon, dans ta classe générique tu prendra en compte un paramètre indiquant le type de moteur SQL utilisé (MySQL, SQLite, SQL Server, Oracle, etc...) et dans pas mal de tes fonctions, tu te retrouveras avec un switch pour écrire tes requêtes en fonction du moteur.

    J'en ai fait une qui gère seulement MySQL et SQLite et je me suis rapidement retrouvé avec beaucoup de code pour pas grand chose.
    Blog - Articles - Framework

    MSDN vous aide, si si, alors n'hésitez pas à y faire un tour avant de poser une question.
    Ah, et n'oubliez pas, Google peut répondre à la majorité de vos questions.

  5. #5
    Expert éminent sénior

    Avatar de Philippe Vialatte
    Homme Profil pro
    Architecte technique
    Inscrit en
    Juillet 2004
    Messages
    3 029
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Architecte technique
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Juillet 2004
    Messages : 3 029
    Points : 12 465
    Points
    12 465
    Par défaut
    +1

    Si tu veux voir la prise de tête que c'est de gerer tous ces dialectes, recupere le code source de NHibernate ou de Subsonic, et jette un oeil aux providers...

    Grosso modo, tu dois te taper un provider par base de donnees...

    Si c'est un projet perso, base toit sur un des deux projets existant, ca devrait bien t'aider...

    Si c'est pour le travail, je te deconseille de paser du temps a reinventer un ORM

    Mon Blog

    The Cake is still a lie !!!



    Vous voulez contribuer à la rubrique .NET ? Contactez-moi par MP.
    Vous voulez rédiger des articles pour la rubrique .NET ? Voici la procédure à suivre.

  6. #6
    Membre à l'essai
    Inscrit en
    Mars 2009
    Messages
    20
    Détails du profil
    Informations forums :
    Inscription : Mars 2009
    Messages : 20
    Points : 11
    Points
    11
    Par défaut
    Merci pour vos réponses.

    Je garde la partie générique pour la base, genre je l'utilise comme brique d'accès dans ma couche DAO, en lui passant les requêtes SQL ou le nom des procédures stockées en paramètre.

    Je n'ai pas prévu d'aller jusqu'à rendre la partie SQL générique car je suis bien conscient que ceci sera très difficile en raison de l'implémentation SQL différente selon le SGBD (Transact SQL, PL/SQL...) et très chronophage.

    De toute façon, je travaille principalement avec SQL Server... Au pire je m'amuserai avec le SQL quand j'aurais l'occasion de passer sur Oracle ou un autre SGBDR, en fonction de la motivation ou du temps libre

    La classe est pour des projets persos pour le moment mais sera de toute façon réutilisée ou modifiée si besoin pour le travail.

    Mais effectivement, je n'irai pas jusqu'à réinventer un ORM, ce qui serai inutile et contre productif. Je vais quand même jeter un coup d'oeil à NHibernate, histoire d'avoir une alternative.

    Entre les trois choix de base, je me demandais lequel était le plus élégant en terme de simplicité et de performance. Je me demande si le fait de créer sans arrêt des objets d'accès ne risquait pas de gêner les performances en cas de montée en charge, sur un projet ASP.NET par exemple (d'où le départ sur une classe avec des méthodes statique).

  7. #7
    Expert éminent sénior

    Avatar de Philippe Vialatte
    Homme Profil pro
    Architecte technique
    Inscrit en
    Juillet 2004
    Messages
    3 029
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Architecte technique
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Juillet 2004
    Messages : 3 029
    Points : 12 465
    Points
    12 465
    Par défaut
    Citation Envoyé par PlayerOne Voir le message
    Entre les trois choix de base, je me demandais lequel était le plus élégant en terme de simplicité et de performance. Je me demande si le fait de créer sans arrêt des objets d'accès ne risquait pas de gêner les performances en cas de montée en charge, sur un projet ASP.NET par exemple (d'où le départ sur une classe avec des méthodes statique).
    Ca depends de quels objets tu parles, mais si tu parles des connection, c'est une bonne pratique de fermer les connections le plus vite possible, pour qu'elles puissent retourner dans le pool...

    Typiquement, pour un acces aux donnes, tu vas preparer ta requete, puis creer la connection, executer la requete, et fermer la connection juste ares (ou encore mieux, utiliser using)

    Mon Blog

    The Cake is still a lie !!!



    Vous voulez contribuer à la rubrique .NET ? Contactez-moi par MP.
    Vous voulez rédiger des articles pour la rubrique .NET ? Voici la procédure à suivre.

  8. #8
    Membre à l'essai
    Inscrit en
    Mars 2009
    Messages
    20
    Détails du profil
    Informations forums :
    Inscription : Mars 2009
    Messages : 20
    Points : 11
    Points
    11
    Par défaut
    Citation Envoyé par Philippe Vialatte Voir le message
    Ca depends de quels objets tu parles, mais si tu parles des connection, c'est une bonne pratique de fermer les connections le plus vite possible, pour qu'elles puissent retourner dans le pool...

    Typiquement, pour un acces aux donnes, tu vas preparer ta requete, puis creer la connection, executer la requete, et fermer la connection juste ares (ou encore mieux, utiliser using)
    Dans mon cas et dans l'exemple de classe DataProvider, à chaque exécution de requête, il va instancier un nouvel objet DbConnection et DbCommand. En supposant que l'on exécute plusieurs requête à la suite (dans une page ASP.NET par exemple), l'opération n'est-elle pas trop coûteuse au niveau du fonctionnement ?

    L'utilisation du pool de connexion .NET permet-elle bien de créer des séries d'objet DbConnection puis de les oublier, ceux-ci récupérant à chaque fois que c'est possible une connexion libre dans le pool ?

  9. #9
    Expert éminent sénior

    Avatar de Philippe Vialatte
    Homme Profil pro
    Architecte technique
    Inscrit en
    Juillet 2004
    Messages
    3 029
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Architecte technique
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Juillet 2004
    Messages : 3 029
    Points : 12 465
    Points
    12 465
    Par défaut
    Citation Envoyé par PlayerOne Voir le message
    Dans mon cas et dans l'exemple de classe DataProvider, à chaque exécution de requête, il va instancier un nouvel objet DbConnection et DbCommand. En supposant que l'on exécute plusieurs requête à la suite (dans une page ASP.NET par exemple), l'opération n'est-elle pas trop coûteuse au niveau du fonctionnement ?
    Non, le cout d'instanciation est minime, le plus cher est de creer une connection, mais une fois qu'elle a ete creee, elle se retrouve dans le pool

    L'utilisation du pool de connexion .NET permet-elle bien de créer des séries d'objet DbConnection puis de les oublier, ceux-ci récupérant à chaque fois que c'est possible une connexion libre dans le pool ?
    Vi, exactement

    Mon Blog

    The Cake is still a lie !!!



    Vous voulez contribuer à la rubrique .NET ? Contactez-moi par MP.
    Vous voulez rédiger des articles pour la rubrique .NET ? Voici la procédure à suivre.

  10. #10
    Membre à l'essai
    Inscrit en
    Mars 2009
    Messages
    20
    Détails du profil
    Informations forums :
    Inscription : Mars 2009
    Messages : 20
    Points : 11
    Points
    11
    Par défaut
    Non, le cout d'instanciation est minime, le plus cher est de creer une connection, mais une fois qu'elle a ete creee, elle se retrouve dans le pool
    Ok, merci pour les infos

  11. #11
    Rédacteur
    Avatar de SaumonAgile
    Homme Profil pro
    Team leader
    Inscrit en
    Avril 2007
    Messages
    4 028
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Team leader
    Secteur : Conseil

    Informations forums :
    Inscription : Avril 2007
    Messages : 4 028
    Points : 6 334
    Points
    6 334
    Par défaut
    Personnellement, je préfère garder les méthodes statiques. Je gère ensuite un contexte par thread pour les paramètres de connexion.
    L'utilisation courante de cette classe est telle que la chaîne de connexion est presque toujours la même sauf cas particulier.
    Je crée une propriété statique dans ma classe de contexte (DatabaseContext) nommée Current et une autre propriété Default.
    J'ai une méthode statique Add et une méthode Remove qui prennent en paramètre un DatabaseContext. Je gère un dictionnaire de stack indexé sur les threads pour savoir quelle est le contexte actif.
    Il ne reste plus qu'à utiliser DatabaseContext.Current.ConnectionString dans les opérations de la couche data access.
    Et comme j'aime bien me simplifier les choses, DatabaseContext implémente IDisposable (Dispose appelle le Remove) me permettant d'écrire des choses comme ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    using (var context = new DatabaseContext(/* un ID de connection string ou une connection string directement*/)
    {
        // Appel des méthodes de la couche data access
    }
    J'aurais pu le rajouter dans l'article mais je me suis dit que ça ferait un peu plus de nourriture pour le cerveau.
    Besoin d'un MessageBox amélioré ? InformationBox pour .NET 1.1, 2.0, 3.0, 3.5, 4.0 sous license Apache 2.0.

    Bonnes pratiques pour les accès aux données
    Débogage efficace en .NET
    LINQ to Objects : l'envers du décor

    Mon profil LinkedIn - MCT - MCPD WinForms - MCTS Applications Distribuées - MCTS WCF - MCTS WCF 4.0 - MCTS SQL Server 2008, Database Development - Mon blog - Twitter

  12. #12
    Membre à l'essai
    Inscrit en
    Mars 2009
    Messages
    20
    Détails du profil
    Informations forums :
    Inscription : Mars 2009
    Messages : 20
    Points : 11
    Points
    11
    Par défaut
    Citation Envoyé par SaumonAgile Voir le message
    Personnellement, je préfère garder les méthodes statiques. Je gère ensuite un contexte par thread pour les paramètres de connexion.
    L'utilisation courante de cette classe est telle que la chaîne de connexion est presque toujours la même sauf cas particulier.
    Je crée une propriété statique dans ma classe de contexte (DatabaseContext) nommée Current et une autre propriété Default.
    J'ai une méthode statique Add et une méthode Remove qui prennent en paramètre un DatabaseContext. Je gère un dictionnaire de stack indexé sur les threads pour savoir quelle est le contexte actif.
    Il ne reste plus qu'à utiliser DatabaseContext.Current.ConnectionString dans les opérations de la couche data access.
    Et comme j'aime bien me simplifier les choses, DatabaseContext implémente IDisposable (Dispose appelle le Remove) me permettant d'écrire des choses comme ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    using (var context = new DatabaseContext(/* un ID de connection string ou une connection string directement*/)
    {
        // Appel des méthodes de la couche data access
    }
    J'aurais pu le rajouter dans l'article mais je me suis dit que ça ferait un peu plus de nourriture pour le cerveau.
    Effectivement...

    Si je comprend bien, cette méthode permet de changer la propriété ConnectionString avant de faire une série d'opération vers la base dans la couche DAO, avec un système de sauvegarde de la configuration en pile et par thread afin d'éviter les effets de bords si un thread réalise des opérations et qu'un autre tente en simultané d'en faire vers une autre base...

    Ce qui revient finalement à modifier avant chaque opération la chaîne de connexion avec en plus une méthode qui permet de rendre thread-safe les méthodes statiques de la classe ?

    Où alors j'ai rien compris

  13. #13
    Expert éminent sénior

    Avatar de Philippe Vialatte
    Homme Profil pro
    Architecte technique
    Inscrit en
    Juillet 2004
    Messages
    3 029
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Architecte technique
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Juillet 2004
    Messages : 3 029
    Points : 12 465
    Points
    12 465
    Par défaut
    Le code que t'as montre saumonagile veut simplement dire qu'il injecte la chaine de connection dans le constructeur du datacontext avant de l'utiliser.

    Comme je suis tombe la-dessus hier, je te joins un lien qui risque de t'interesser

    http://davybrion.com/blog/2009/08/bu...-layer-series/

    Mon Blog

    The Cake is still a lie !!!



    Vous voulez contribuer à la rubrique .NET ? Contactez-moi par MP.
    Vous voulez rédiger des articles pour la rubrique .NET ? Voici la procédure à suivre.

  14. #14
    Rédacteur
    Avatar de SaumonAgile
    Homme Profil pro
    Team leader
    Inscrit en
    Avril 2007
    Messages
    4 028
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Team leader
    Secteur : Conseil

    Informations forums :
    Inscription : Avril 2007
    Messages : 4 028
    Points : 6 334
    Points
    6 334
    Par défaut
    En fait le code que j'ai fourni permet de surcharger ponctuellement le contexte de la base de données pour utiliser une autre base que celle définie par défaut.
    Il n'y a pas besoin de créer un contexte à chaque opération. Il y a un contexte par défaut transparent, et la possibilité d'empiler autant de contextes personnalisés que nécessaire. C'est ce que disait PlayerOne, sauf que le contexte explicite n'est pas obligatoire, c'est une "surcharge locale" du contexte par défaut.
    Le contexte n'est pas limité à uniquement la chaine de connexion, on peut mettre tout ce qu'on veut dans le contexte.
    Dans mon projet InfoBox, le contexte me sert à stocker (entre autres) le design par défaut des messages.
    Besoin d'un MessageBox amélioré ? InformationBox pour .NET 1.1, 2.0, 3.0, 3.5, 4.0 sous license Apache 2.0.

    Bonnes pratiques pour les accès aux données
    Débogage efficace en .NET
    LINQ to Objects : l'envers du décor

    Mon profil LinkedIn - MCT - MCPD WinForms - MCTS Applications Distribuées - MCTS WCF - MCTS WCF 4.0 - MCTS SQL Server 2008, Database Development - Mon blog - Twitter

  15. #15
    Membre à l'essai
    Inscrit en
    Mars 2009
    Messages
    20
    Détails du profil
    Informations forums :
    Inscription : Mars 2009
    Messages : 20
    Points : 11
    Points
    11
    Par défaut
    Citation Envoyé par SaumonAgile Voir le message
    En fait le code que j'ai fourni permet de surcharger ponctuellement le contexte de la base de données pour utiliser une autre base que celle définie par défaut.
    Il n'y a pas besoin de créer un contexte à chaque opération. Il y a un contexte par défaut transparent, et la possibilité d'empiler autant de contextes personnalisés que nécessaire.
    L'utilisation de ce système de contexte pour gérer la configuration vers la base de données est intéressante, c'est une idée à creuser. Ça peut-être une bonne alternative pour un accès occasionnel dans l'application à une autre base.

    Merci pour tous ces renseignements.

    Par contre, j'ai une dernière question : j'ai vu plusieurs articles sur le Net utilisant un Pattern Singleton pour gérer les accès BDD, et d'autres disant de ne pas utiliser ce genre de méthode.

    En quoi l'utilisation d'un Singleton peut être problématique par rapport à une classe statique, dans le cas d'une application WinForm par exemple ?

    Le cas d'ASP.NET étant différent, en raison du contexte multi-utilisateur...

  16. #16
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 749
    Points
    39 749
    Par défaut
    Citation Envoyé par PlayerOne Voir le message
    En quoi l'utilisation d'un Singleton peut être problématique par rapport à une classe statique, dans le cas d'une application WinForm par exemple ?
    Ben un singleton ou une classe statique, ça revient un peu au même en fait... Si tu veux faire les choses vraiment proprement, l'idéal est d'utiliser l'injection de dépendence pour gérer ton objet d'accès aux données. Mais bon, si c'est pas une très grosse appli c'est peut-être un peu trop pour tes besoins...

Discussions similaires

  1. Réponses: 2
    Dernier message: 05/08/2012, 21h05
  2. instanciation d'une classe d'acces aux données
    Par tortuegenie dans le forum ASP.NET
    Réponses: 12
    Dernier message: 10/09/2009, 11h55
  3. [Debutant] Classe d'acces aux données
    Par Keldrhyn dans le forum Access
    Réponses: 4
    Dernier message: 18/02/2007, 20h30
  4. Réponses: 5
    Dernier message: 24/05/2006, 23h53
  5. Réponses: 13
    Dernier message: 23/02/2006, 11h42

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo