Précédent   Forum des professionnels en informatique > PHP > PHP & SGBD > ORM > Doctrine
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse Proposer ce sujet en actualité
 
Outils de la discussion
Publicité
'
Vieux 28/03/2011, 10h06   #1
Membre chevronné
 
Avatar de Herode
 
Développeur Web
Inscription : mars 2005
Messages : 769
Détails du profil
Informations personnelles :
Localisation : France, Savoie (Rhône Alpes)

Informations professionnelles :
Activité : Développeur Web

Informations forums :
Inscription : mars 2005
Messages : 769
Points : 788
Points : 788
Par défaut Requête select imbriquée dans un where not in

Messieurs dames,

soit une hiérarchie de catégories. Chaque catégorie peut avoir plusieurs parents et plusieurs enfants.

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
 
Category:
  columns:
    tag:
      type: string(20)
 
CategoryHasCategory:
  columns:
    child_category_id:
      type: integer
      primary: true
      notnull: true
    parent_category_id:
      type: integer
      primary: true
      notnull: true
  relations:
    ParentCategory:
      class: Category
      local: parent_category_id
      foreignAlias: LinksToChildrenCategories
    ChildCategory:
      class: Category
      local: child_category_id
      foreignAlias: LinksToParentCategories
Je cherche la liste des catégories racines, donc les catégories qui ne sont pas présentes dans CategoryHasCategory en tant que catégories filles. En SQL, facile :
Code :
select * from Category where id not in (select distinct(child_category_id) from CategoryHasCategory)
Malheureusement, Doctrine ne l'entend pas de cette oreille :
Code :
1
2
3
4
5
6
7
8
9
 
    public static function getRootCategoriesQuery(Doctrine_Query $q = null) {
	if(!$q) {
	    $q = self::getInstance()->createQuery();
	}
 
	$rootAlias = $q->getRootAlias();
	return $q->andWhere("$rootAlias.id NOT IN(SELECT CategoryHasCategory.child_category_id FROM CategoryHasCategory)");
    }
donne comme code SQL généré par Doctrine :
Code :
1
2
3
4
 
	$q = CategoryTable::getRootCategoriesQuery()->execute();
---> SQL généré : 
SELECT c.* FROM category c, category_has_category c2 WHERE (c.id NOT SELECT c2.child_category_id FROM CategoryHasCategory IN ()) - ()
N'importe quoi, donc...

Je vais provisoirement contourner le problème en construisant le tableau des ids des catégories filles et en le passant au addWhere en argument, ce qui élimine la requête imbriquée. Mais ce qui m'intéresserait serait plutôt de construire le DQL avec requête imbriquée pour que Doctrine le comprenne.
Herode est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 28/03/2011, 10h30   #2
Modérateur
 
Avatar de Michel Rotta
 
Homme Michel Rotta
Responsable d'exploitation informatique
Inscription : septembre 2005
Messages : 4 913
Détails du profil
Informations personnelles :
Nom : Homme Michel Rotta
Âge : 49
Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

Informations professionnelles :
Activité : Responsable d'exploitation informatique
Secteur : Distribution

Informations forums :
Inscription : septembre 2005
Messages : 4 913
Points : 7 505
Points : 7 505
As-tu regardé du côté de Doctrine_RawSql ?
__________________
Si tu donnes un poisson à un homme, il mangera un jour. Si tu lui apprends à pêcher, il mangera toujours (Lao Tseu).
  • Pensez à valoriser les réponses pertinantes, cliquez sur le bouton vert +1 pour indiquer votre accord avec la solution proposée.
  • Pensez à utiliser la balise [code] pour afficher du code, elle est cachée sous le bouton [#] dans l'éditeur.
  • Une discussion est terminée ? Alors le bouton est votre ami !
Michel Rotta est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 28/03/2011, 11h05   #3
Membre chevronné
 
Avatar de Herode
 
Développeur Web
Inscription : mars 2005
Messages : 769
Détails du profil
Informations personnelles :
Localisation : France, Savoie (Rhône Alpes)

Informations professionnelles :
Activité : Développeur Web

Informations forums :
Inscription : mars 2005
Messages : 769
Points : 788
Points : 788
Hélas oui. Note que dans l'idéal, avec toutes les vertus que les concepteurs de Symfony et de Doctrine prêtent à leur produit, je m'attends plutôt à pouvoir utiliser le DQL fourni par cet ORM. Je déduis de ta question que ce n'est pas possible, donc ?

Côté RawSql, j'ai d'autres problèmes.
Code :
1
2
3
4
5
	$q = new Doctrine_RawSql();
	$q->select('distinct {c.child_category_id}')
		->from('category_has_category c')
		->addComponent('c', 'CategoryHasCategory')
		->execute();
me fait bien une requête correcte, mais sans le 'distinct'.

Rien de grave bien sûr, je peux dédoublonner moi-même les résultats. Mais une fois de plus, j'ai l'impression que le couple Doctrine/Symfony rend compliquée une chose qui devrait être simple...
Herode est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 28/03/2011, 11h17   #4
Membre chevronné
 
Avatar de Herode
 
Développeur Web
Inscription : mars 2005
Messages : 769
Détails du profil
Informations personnelles :
Localisation : France, Savoie (Rhône Alpes)

Informations professionnelles :
Activité : Développeur Web

Informations forums :
Inscription : mars 2005
Messages : 769
Points : 788
Points : 788
Ha oui, et puis j'ai aussi ça comme résultats dans mes traces :

Code :
1
2
3
4
5
6
 
	$q = new Doctrine_RawSql();
	$rows = $q->select('{c.child_category_id}')
		->from('category_has_category c')
		->addComponent('c', 'CategoryHasCategory')
		->execute(Doctrine_Core::HYDRATE_SCALAR);
Citation:
--->
Mar 28 09:13:06 symfony [info] {Doctrine_Connection_Statement} execute : SELECT c.child_category_id AS c__child_category_id, c.parent_category_id AS c__parent_category_id FROM category_has_category c - (5)
De toute évidence, Doctrine se fiche pas mal qu'on ait besoin d'une colonne ou de toutes, tout comme il se fiche de la clause DISTINCT. En outre, des logs additionnels montrent que Doctrine me renvoie une série d'objets de la classe CategoryHasCategory et non pas un tableau associatif.

Comment faire pour qu'il effectue la requête demandée ? Ai-je raté quelque chose dans son paramétrage ?
Herode est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 28/03/2011, 12h49   #5
Modérateur
 
Avatar de Michel Rotta
 
Homme Michel Rotta
Responsable d'exploitation informatique
Inscription : septembre 2005
Messages : 4 913
Détails du profil
Informations personnelles :
Nom : Homme Michel Rotta
Âge : 49
Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

Informations professionnelles :
Activité : Responsable d'exploitation informatique
Secteur : Distribution

Informations forums :
Inscription : septembre 2005
Messages : 4 913
Points : 7 505
Points : 7 505
Effectivement, doctrine 1 ne sait pas faire de requêtes imbriquées. C'est indiqué dans la documentation (mais où ? ! ), en tout cas, je l'y ai lu.

Il n'y a aucun paramétrages général qui permettraient de simplifier... Hélas.

Le problème des requêtes imbriquées et de Doctrine, c'est la portabilité. En effet, l'objectif de Doctrine est de permettre à ton code de travailler sur n'importe quel moteur de base de données sans avoir à réécrire du code. Ce qui, dans certains cas, à une tendance gênante mais naturel à compliquer largement la situation.

A priori, pour que les commandes sql passent bien dans doctrine elles doivent être en MAJUSCULE.
Code :
$q->select('DISTINCT {c.child_category_id}')
__________________
Si tu donnes un poisson à un homme, il mangera un jour. Si tu lui apprends à pêcher, il mangera toujours (Lao Tseu).
  • Pensez à valoriser les réponses pertinantes, cliquez sur le bouton vert +1 pour indiquer votre accord avec la solution proposée.
  • Pensez à utiliser la balise [code] pour afficher du code, elle est cachée sous le bouton [#] dans l'éditeur.
  • Une discussion est terminée ? Alors le bouton est votre ami !
Michel Rotta est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 28/03/2011, 14h25   #6
Membre chevronné
 
Avatar de Herode
 
Développeur Web
Inscription : mars 2005
Messages : 769
Détails du profil
Informations personnelles :
Localisation : France, Savoie (Rhône Alpes)

Informations professionnelles :
Activité : Développeur Web

Informations forums :
Inscription : mars 2005
Messages : 769
Points : 788
Points : 788
Citation:
Envoyé par Michel Rotta Voir le message
Effectivement, doctrine 1 ne sait pas faire de requêtes imbriquées. C'est indiqué dans la documentation (mais où ? ! ), en tout cas, je l'y ai lu.
Leur doc n'est pas à jour en ce cas : DQL/subqueries (1.2)

Pour le raw sql, j'ai essayé avec des majuscules, des minuscules, des caractères cyrilliques, en dansant devant mon bureau, en ahanant des litanies mystiques, en string, en costard cravate, avec ou sans gants cloutés. Rien n'y fait.

Je pense que c'est un complot.
Herode est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 28/03/2011, 14h43   #7
Modérateur
 
Avatar de Michel Rotta
 
Homme Michel Rotta
Responsable d'exploitation informatique
Inscription : septembre 2005
Messages : 4 913
Détails du profil
Informations personnelles :
Nom : Homme Michel Rotta
Âge : 49
Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

Informations professionnelles :
Activité : Responsable d'exploitation informatique
Secteur : Distribution

Informations forums :
Inscription : septembre 2005
Messages : 4 913
Points : 7 505
Points : 7 505
Il n'y a pas contradiction avec ce que je dis. DQL ne supporte pas les sous requêtes, il faut les exprimer en SQL.

Après, il faudrait que je fasse des tests avec ton modèle et du temps, les deux me manquent, le deuxième cruellement...
__________________
Si tu donnes un poisson à un homme, il mangera un jour. Si tu lui apprends à pêcher, il mangera toujours (Lao Tseu).
  • Pensez à valoriser les réponses pertinantes, cliquez sur le bouton vert +1 pour indiquer votre accord avec la solution proposée.
  • Pensez à utiliser la balise [code] pour afficher du code, elle est cachée sous le bouton [#] dans l'éditeur.
  • Une discussion est terminée ? Alors le bouton est votre ami !
Michel Rotta est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Proposer ce sujet en actualité
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 23h42.


 
 
 
 
Partenaires

Hébergement Web