Précédent   Forum du club des développeurs et IT Pro > C et C++ > Bibliothèques > Qt > Outils > Bibliothèques > QxOrm
QxOrm Forum d'entraide pour QxOrm
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse
 
Outils de la discussion
Publicité
'
Vieux 07/01/2013, 21h13   #1
djarBoy
Membre à l'essai
 
Inscription : juin 2008
Messages : 142
Détails du profil
Informations forums :
Inscription : juin 2008
Messages : 142
Points : 20
Points : 20
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 !
djarBoy est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 08/01/2013, 09h51   #2
QxOrm
Membre Expert
 
Inscription : avril 2010
Messages : 331
Détails du profil
Informations forums :
Inscription : avril 2010
Messages : 331
Points : 1 218
Points : 1 218


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 :
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 :
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 :
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 :
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 :
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.

Tutoriel qxBlog
: gestion de blogs en C++/Qt.
Tutoriel qxClientServer : création d'un serveur d'applications en C++/Qt.
QxOrm est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 08/01/2013, 20h28   #3
djarBoy
Membre à l'essai
 
Inscription : juin 2008
Messages : 142
Détails du profil
Informations forums :
Inscription : juin 2008
Messages : 142
Points : 20
Points : 20
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 ?
djarBoy est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 09/01/2013, 09h18   #4
QxOrm
Membre Expert
 
Inscription : avril 2010
Messages : 331
Détails du profil
Informations forums :
Inscription : avril 2010
Messages : 331
Points : 1 218
Points : 1 218
Citation:
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 :
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.

Tutoriel qxBlog
: gestion de blogs en C++/Qt.
Tutoriel qxClientServer : création d'un serveur d'applications en C++/Qt.
QxOrm est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 09/01/2013, 09h45   #5
djarBoy
Membre à l'essai
 
Inscription : juin 2008
Messages : 142
Détails du profil
Informations forums :
Inscription : juin 2008
Messages : 142
Points : 20
Points : 20
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 :
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 !!
djarBoy est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 09/01/2013, 10h10   #6
QxOrm
Membre Expert
 
Inscription : avril 2010
Messages : 331
Détails du profil
Informations forums :
Inscription : avril 2010
Messages : 331
Points : 1 218
Points : 1 218
Citation:
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 :
Citation:
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 :
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.

Tutoriel qxBlog
: gestion de blogs en C++/Qt.
Tutoriel qxClientServer : création d'un serveur d'applications en C++/Qt.
QxOrm est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 10/01/2013, 09h53   #7
djarBoy
Membre à l'essai
 
Inscription : juin 2008
Messages : 142
Détails du profil
Informations forums :
Inscription : juin 2008
Messages : 142
Points : 20
Points : 20
Pour info, je vais également essayer de concevoir l'opérateur UPPER, afin de pouvoir écrire ce type de requete:

Code :
SELECT * FROM Patient WHERE UPPER(Patient.name) = :patientLastName
Ça ne doit pas être trop différent de ce que tu proposes.
djarBoy est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 10/01/2013, 15h25   #8
QxOrm
Membre Expert
 
Inscription : avril 2010
Messages : 331
Détails du profil
Informations forums :
Inscription : avril 2010
Messages : 331
Points : 1 218
Points : 1 218
Citation:
Ça ne doit pas être trop différent de ce que tu proposes.
En effet, juste la fonction toString() à modifier, quelque chose comme ça :
Code :
return "UPPER(" + sColumn + ") = " + sKey;
__________________
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.

Tutoriel qxBlog
: gestion de blogs en C++/Qt.
Tutoriel qxClientServer : création d'un serveur d'applications en C++/Qt.
QxOrm est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 20/01/2013, 15h39   #9
djarBoy
Membre à l'essai
 
Inscription : juin 2008
Messages : 142
Détails du profil
Informations forums :
Inscription : juin 2008
Messages : 142
Points : 20
Points : 20
Pour information, ce que tu m'as donné fonctionne très bien, mais il y a quand même un souci.

Vu que les mots clés or_(...) and_, etc... renvoient une référence vers l'objet qx::SqlQery et non pas ma classe, je suis obligé de faire ma requête en plusieurs temps...
djarBoy est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 21/01/2013, 10h37   #10
QxOrm
Membre Expert
 
Inscription : avril 2010
Messages : 331
Détails du profil
Informations forums :
Inscription : avril 2010
Messages : 331
Points : 1 218
Points : 1 218
Citation:
Vu que les mots clés or_(...) and_, etc... renvoient une référence vers l'objet qx::QxSqlQery et non pas ma classe, je suis obligé de faire ma requête en plusieurs temps...
Tu peux essayer de télécharger cette version BETA :
http://www.qxorm.com/version/QxOrm_1.2.5_BETA_06.zip

Normalement ton compilateur C++ devrait supporter les types de retour covariant (tous les compilateurs "récents" le supportent), donc ça devrait fonctionner.
Avec cette version BETA, tu changes rien à ton code, et tu ajoutes juste à ta classe :
* dans le .h :
QX_SQL_QUERY_DERIVED_IMPL_COVARIANT_RETURN_TYPE_HPP(MyClassName)
* dans le .cpp :
QX_SQL_QUERY_DERIVED_IMPL_COVARIANT_RETURN_TYPE_CPP(MyClassName)

Avec ça, tu pourras écrire ta requête normalement
Tiens moi au courant stp pour me dire si ça fonctionne bien ou pas...
__________________
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.

Tutoriel qxBlog
: gestion de blogs en C++/Qt.
Tutoriel qxClientServer : création d'un serveur d'applications en C++/Qt.
QxOrm est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 27/01/2013, 15h25   #11
djarBoy
Membre à l'essai
 
Inscription : juin 2008
Messages : 142
Détails du profil
Informations forums :
Inscription : juin 2008
Messages : 142
Points : 20
Points : 20
Je vais tester ça très bientôt ! Merci beaucoup !
djarBoy est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Cette discussion est résolue.
Outils de la discussion

Navigation rapide


Fuseau horaire GMT +2. Il est actuellement 07h11.


 
 
 
 
Partenaires

Hébergement Web