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

QxOrm Discussion :

Conseil sur l'implémentation des fonctions spécifiques aux différents SGBD


Sujet :

QxOrm

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre très actif
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    151
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 151
    Par défaut Conseil sur l'implémentation des fonctions spécifiques aux différents SGBD
    Hello !

    J'aimerais avoir votre avis sur ce point:
    postgresql propose une fonction spécifique qui s'appelle "ilike" qui est semblable à un like dans une requête mais en insensible à la casse.
    Ma question est comment puis-je faire pour l'utiliser au sein de QxOrm, je comprends bien que l'objectif de QxOrm n'est pas d'implémenter ces fonctions spécifiques, mais du coup, c'est un peu délicat et je préfère demander des avis avant de me décider....

    Plus généralement et idéalement, j'aimerais faire un LIKE insensible à la casse qui soit indépendant du SGBD, mais ma question s'étend également à d'autres fonctions spécifiques au langage comme "UPPER" etc...

    Je pourrais utiliser une requête brute par le biais de QxQuery, mais ça me semble pas terrible car ça m'empêche d'utiliser ce que tu as fait avec la syntaxe des requêtes du type query.where("toto").like("tata%");

    Merci par avance !

  2. #2
    Membre Expert

    Profil pro
    Inscrit en
    Avril 2010
    Messages
    482
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 482
    Par défaut


    C'est une excellente question
    Et je pense que je vais l'ajouter dans la FAQ si on arrive à faire quelque chose de sympa.

    Je pense que tu peux essayer de surcharger la classe qx::QxSqlQuery pour ajouter tes propres fonctionnalités (spécifiques à un SGBD par exemple).

    Chaque élément SQL doit implémenter l'interface qx::dao::detail::IxSqlElement. Tu peux donc te créer tes propres éléments SQL.
    Par exemple, si on veut implémenter ta fonction ILIKE, on pourrait procéder comme ceci :

    * fichier MySqlElementILIKE.h :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    class MySqlElementILIKE : public qx::dao::detail::IxSqlElement
    {
     
    public:
     
       MySqlElementILIKE(int index) : qx::dao::detail::IxSqlElement(index) { ; }
       virtual ~MySqlElementILIKE() { ; }
     
       virtual QString toString() const;
       virtual void resolve(QSqlQuery & query) const;
       virtual void postProcess(QString & sql) const;
     
    };
     
    typedef boost::shared_ptr<MySqlElementILIKE> MySqlElementILIKE_ptr;
    * fichier MySqlElementILIKE.cpp :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    QString MySqlElementILIKE::toString() const
    {
       qAssert((m_lstColumns.count() == 1) && (m_lstKeys.count() == 1));
       QString sColumn(m_lstColumns.at(0)), sKey(m_lstKeys.at(0));
       qAssert(! sColumn.isEmpty() && ! sKey.isEmpty());
       return sColumn + " ILIKE " + sKey;
    }
     
    void MySqlElementILIKE::resolve(QSqlQuery & query) const
    {
       qAssert((m_lstKeys.count() == 1) && (m_lstValues.count() == 1));
       QString sKey(m_lstKeys.at(0));
       QVariant vValue(m_lstValues.at(0));
     
       bool bQuestionMark = (qx::QxSqlDatabase::getSingleton()->getSqlPlaceHolderStyle() == qx::QxSqlDatabase::ph_style_question_mark);
       if (bQuestionMark) { query.addBindValue(vValue); }
       else { query.bindValue(sKey, vValue); }
    }
     
    void MySqlElementILIKE::postProcess(QString & sql) const
    {
       Q_UNUSED(sql);
    }
    * fichier MySqlQuery.h :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    class MySqlQuery : public qx::QxSqlQuery
    {
     
    public:
     
       MySqlQuery() : qx::QxSqlQuery() { ; }
       MySqlQuery(const QString & sQuery) : qx::QxSqlQuery(sQuery) { ; }
       MySqlQuery(const char * sQuery) : qx::QxSqlQuery(sQuery) { ; }
       virtual ~MySqlQuery() { ; }
     
       MySqlQuery & ilike(const QString & val);
       // ...
       // Ici on peut ajouter toutes les fonctions spécifiques à un SGBD
     
    };
    * fichier MySqlQuery.cpp :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    MySqlQuery & MySqlQuery::ilike(const QString & val)
    {
       if (! m_pSqlElementTemp)
       { qDebug("[QxOrm] MySqlQuery : '%s'", "invalid SQL query, need a column name"); qAssert(false); return (* this); }
     
       MySqlElementILIKE_ptr p;
       p.reset(new MySqlElementILIKE(m_iSqlElementIndex++));
       p->clone(m_pSqlElementTemp.get());
       QVariant var = QVariant(val);
       p->setValue(var);
     
       m_lstSqlElement.append(p);
       m_pSqlElementTemp.reset();
       return (* this);
    }
    A présent tu peux utiliser la classe MySqlQuery de la même façon que qx::QxSqlQuery :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    MySqlQuery query;
    query.where("toto").ilike("tata%");
    // ...
    Je n'ai pas testé et j'écris ça un peu vite, tu me diras si ça fonctionne ou non...
    Le site de la bibliothèque QxOrm : bibliothèque C++ de gestion de données (Mapping Objet Relationnel ou ORM) basée sur les frameworks Qt et boost.
    QxEntityEditor : éditeur graphique pour la bibliothèque QxOrm (application multi-plateforme pour gérer graphiquement le modèle d'entités).

    Tutoriel : installer un environnement de développement avec QxOrm sous Windows.
    Tutoriel qxBlog : gestion de blogs en C++/Qt.
    Tutoriel qxClientServer : création d'un serveur d'applications en C++/Qt.

  3. #3
    Membre très actif
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    151
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 151
    Par défaut
    Réponse très intéressante !!

    Je vais regarder ça, après réflexion, ce que tu proposes me semble tout à fait bien

    Reste à savoir où je fais ma spécialisation car l'idée est quand même que mon logiciel reste autant compatible que possible avec les autres SGBD.

    Peut être faudrait-il un concept supplémentaire: un genre de propriété fallbackTo(&This::like) qui retombe dans une fonctionnalité plus compatible quand "ilike" n'est pas géré (dans le cas présent: like).

    Qu'en penses-tu ?

  4. #4
    Membre Expert

    Profil pro
    Inscrit en
    Avril 2010
    Messages
    482
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 482
    Par défaut
    Peut être faudrait-il un concept supplémentaire: un genre de propriété fallbackTo(&This::like) qui retombe dans une fonctionnalité plus compatible quand "ilike" n'est pas géré (dans le cas présent: like).
    Qu'en penses-tu ?
    Attention à ça : tu risques d'avoir des comportements étranges quand un SGBD ne gère pas la fonction spécifique en question, et ça risque d'être compliqué à déboguer.
    Mais bon, tu peux facilement le faire je pense : à toi d'organiser ton code pour le rendre +/- compatible avec les autres SGBD.
    Au lieu de la classe MySqlQuery telle que je te l'ai écrite, tu fais une interface (IMySqlQuery), et les fonctions spécifiques que tu ajoutes, tu les mets en virtual, par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    class IMySqlQuery : public qx::QxSqlQuery
    {
     
    public:
     
       IMySqlQuery() : qx::QxSqlQuery() { ; }
       IMySqlQuery(const QString & sQuery) : qx::QxSqlQuery(sQuery) { ; }
       IMySqlQuery(const char * sQuery) : qx::QxSqlQuery(sQuery) { ; }
       virtual ~IMySqlQuery() { ; }
     
       virtual IMySqlQuery & ilike(const QString & val);
       // ...
       // Ici on peut ajouter toutes les fonctions spécifiques à un SGBD
     
    };
    Dans cette interface, par défaut, la méthode ilike() appelle like() de la classe de base (qx::QxSqlQuery).
    Ensuite, la classe MySqlQuery n'hérite plus de qx::QxSqlQuery mais de ton interface IMySqlQuery : tu peux en faire une pour postgres, une pour mysql, une pour oracle, etc...
    Le site de la bibliothèque QxOrm : bibliothèque C++ de gestion de données (Mapping Objet Relationnel ou ORM) basée sur les frameworks Qt et boost.
    QxEntityEditor : éditeur graphique pour la bibliothèque QxOrm (application multi-plateforme pour gérer graphiquement le modèle d'entités).

    Tutoriel : installer un environnement de développement avec QxOrm sous Windows.
    Tutoriel qxBlog : gestion de blogs en C++/Qt.
    Tutoriel qxClientServer : création d'un serveur d'applications en C++/Qt.

  5. #5
    Membre très actif
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    151
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 151
    Par défaut
    Ok, ça me semble très bien, je vais analyser ça et le tester.

    Par contre, peux tu m'expliquer un peu ce que fait cette fonction resolve ?
    Et en particulier:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
       bool bQuestionMark = (qx::QxSqlDatabase::getSingleton()->getSqlPlaceHolderStyle() == qx::QxSqlDatabase::ph_style_question_mark);
       if (bQuestionMark) { query.addBindValue(vValue); }
       else { query.bindValue(sKey, vValue); }
    Merci !!

  6. #6
    Membre Expert

    Profil pro
    Inscrit en
    Avril 2010
    Messages
    482
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 482
    Par défaut
    peux-tu m'expliquer un peu ce que fait cette fonction resolve ?
    Avant d'envoyer la requête SQL au SGBD, il a 2 phases :
    1- la génération de la chaîne de caractères à envoyer : c'est la méthode toString() de l'interface qui gère ça ;
    2- le binding des valeurs associées aux paramètres de la requête SQL (placeholder) : c'est la méthode resolve() de l'interface qui gère ça.

    Pour cette 2ème phase, QxOrm propose plusieurs syntaxes pour l'écriture des requêtes, c'est détaillé dans la FAQ (http://www.qxorm.com/qxorm_fr/faq.html#faq_210), voici un extrait :
    La bibliothèque QxOrm supporte trois syntaxes pour l'écriture des paramètres SQL.
    Le type de syntaxe peut être modifié de façon globale à un projet en utilisant la méthode suivante : qx::QxSqlDatabase::getSingleton()->setSqlPlaceHolderStyle().
    Les trois paramètres possibles pour cette méthode sont :
    - ph_style_2_point_name : "WHERE author.sex = :sex" (syntaxe par défaut) ;
    - ph_style_at_name : "WHERE author.sex = @sex" ;
    - ph_style_question_mark : "WHERE author.sex = ?".
    Concernant le code suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
       bool bQuestionMark = (qx::QxSqlDatabase::getSingleton()->getSqlPlaceHolderStyle() == qx::QxSqlDatabase::ph_style_question_mark);
       if (bQuestionMark) { query.addBindValue(vValue); }
       else { query.bindValue(sKey, vValue); }
    Suivant la syntaxe utilisée, pour binder les valeurs des requêtes SQL, tu as soit une notion d'ordre (si tu utilises "?"), soit une notion clé-valeur (si tu utilises ":zzz", ou "@xxx").
    Le site de la bibliothèque QxOrm : bibliothèque C++ de gestion de données (Mapping Objet Relationnel ou ORM) basée sur les frameworks Qt et boost.
    QxEntityEditor : éditeur graphique pour la bibliothèque QxOrm (application multi-plateforme pour gérer graphiquement le modèle d'entités).

    Tutoriel : installer un environnement de développement avec QxOrm sous Windows.
    Tutoriel qxBlog : gestion de blogs en C++/Qt.
    Tutoriel qxClientServer : création d'un serveur d'applications en C++/Qt.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 2
    Dernier message: 29/10/2006, 18h52
  2. Réponses: 3
    Dernier message: 21/10/2006, 16h03
  3. [1.5][dbutils]Conseil sur mon implémentation ?
    Par elitost dans le forum Langage
    Réponses: 2
    Dernier message: 14/09/2006, 12h43
  4. pointeurs sur les arguments des fonctions?
    Par brunoP dans le forum C
    Réponses: 3
    Dernier message: 14/05/2006, 18h11
  5. Implémentation des fonctions mathématiques
    Par mat.M dans le forum Mathématiques
    Réponses: 9
    Dernier message: 17/06/2002, 16h19

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