2012-04-16 25 views
7

Estoy usando Symfony 2 con Doctrine, y tengo dos entidades unidas en una asociación muchos a muchos. Digamos que tengo dos entidades: Usuario y Grupo, y las tablas relacionadas en db son usuarios, grupos y usuarios_grupos.DQL muchos a muchos y cuente

Me gustaría obtener el top 10 grupos más poblados en DQL, pero no sé la sintaxis para realizar consultas en la tabla de unión (users_groups). Ya busqué en el manual de Doctrine, pero no encontré la solución, creo que todavía tengo mucho que aprender sobre DQL.

en SQL claro que sería:

select distinct group_id, count(*) as cnt from users_groups group by group_id order by cnt desc limit 10 

puede usted por favor me ayude a traducir esto a DQL?

Actualizar (clases):

/** 
* Entity\E_User 
* 
* @ORM\Table(name="users") 
* @ORM\Entity 
*/ 
class E_User 
{ 
    /** 
    * @ORM\ManyToMany(targetEntity="E_Group", cascade={"persist"}) 
    * @ORM\JoinTable(name="users_groups", 
    *  joinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id", onDelete="cascade")}, 
    *  inverseJoinColumns={@ORM\JoinColumn(name="group_id", referencedColumnName="id", onDelete="cascade")} 
    *) 
    */ 

    protected $groups; 

    /** 
    * @var integer $id 
    * 
    * @ORM\Column(name="id", type="integer") 
    * @ORM\Id 
    * @ORM\GeneratedValue(strategy="AUTO") 
    */ 
    private $id; 

    /** 
    * @var string $name 
    * 
    * @ORM\Column(name="name", type="string", length=255) 
    */ 
    private $name; 

    /* ... other attributes & getters and setters ...*/ 
} 


/** 
* Entity\E_Group 
* 
* @ORM\Table(name="groups") 
* @ORM\Entity 
*/ 
class E_Group 
{ 
    /** 
    * @var integer $id 
    * 
    * @ORM\Column(name="id", type="integer") 
    * @ORM\Id 
    * @ORM\GeneratedValue(strategy="AUTO") 
    */ 
    private $id; 

    /** 
    * @var string $name 
    * 
    * @ORM\Column(name="text", type="string", length=255) 
    */ 
    private $name; 

    /* ... other attributes & getters and setters ...*/ 
} 

Respuesta

6

No es fácil sin ver las clases reales, pero adivinando que tienen una relación bidireccional muchos-a-muchos:

$dql = "SELECT g.id, count(u.id) as cnt FROM Entity\Group g " . 
    "JOIN g.users u GROUP BY g.id ORDER BY cnt DESC LIMIT 10;"; 
$query = $em->createQuery($dql); 
$popularGroups = $query->getArrayResult(); 

ACTUALIZACIÓN:

No tiene tiene que usar una relación bidireccional, puede qu Ery al revés:

$dql = "SELECT g.id, count(u.id) as cnt FROM Entity\User u " . 
    "JOIN u.groups g GROUP BY g.id ORDER BY cnt DESC LIMIT 10;"; 
+0

gracias, el problema es que la entidad del grupo no tiene una asociación llamada usuarios. De modo que obtengo la excepción: [Error semántico] línea 0, col 72 cerca de GROUP BY g.id ': Error: Class Entity \ E_Group no tiene asociación llamada users. Actualicé la pregunta con las clases reales. ¿Debo agregar un atributo $ users a la entidad E_Group para hacer la relación bidireccional de muchos a muchos? –

+0

muchas gracias. Terminé con una relación bidireccional, de todos modos. Esa fue solo una consulta ficticia para entender cómo funciona. gracias de nuevo –

0

Para aquellos que quieren construir la consulta con la doctrina de QueryBuilder en lugar de utilizar DQL tomar directamente esta solución.

Tenga en cuenta que mi problema no era conseguir los mejores grupos de usuarios, pero técnicamente el problema es bastante similar al mío. Trabajo con publicaciones (como artículos/publicaciones de blog) y etiquetas que se agregan a las publicaciones. Necesitaba determinar una lista de publicaciones relacionadas (identificadas por las mismas etiquetas). Esa lista debe ser ordenada por relevancia (cuantas más etiquetas tenga otra publicación, más relevante será).

Este es el método de mi clase PostRepository:

/** 
* Finds all related posts sorted by relavance 
* (from most important to least important) using 
* the tags of the given post entity. 
* 
* @param Post $post 
* 
* @return POST[] 
*/ 
public function findRelatedPosts(Post $post) { 
    // build query 
    $q = $this->createQueryBuilder('p') 
     ->addSelect('count(t.id) as relevance') 
     ->innerJoin('p.tags', 't') 
     ->where('t.id IN (:tags)') 
     ->setParameter('tags', $post->getTags()) 
     ->andWhere('p.id != :post') 
     ->setParameter('post', $post->getId()) 
     ->addGroupBy('p.id') 
     ->addOrderBy('relevance', 'DESC') 
     ->getQuery(); 

    // execute query and retrieve database result 
    $r = $q->execute(); 

    // result contains arrays, each array contains 
    // the actual post and the relevance value 
    // --> let's extract the post entities and 
    // forget about the relevance, because the 
    // posts are already sorted by relevance 
    $r = array_map(function ($entry) { 
     // first index is the post, second one 
     // is the relevance, just return the post 
     return reset($entry); 
    }, $r); 

    // array of posts 
    return $r; 
} 

Gracias @ Tom Imrei para usted la solución. También la respuesta #26549597 fue muy útil.

Cuestiones relacionadas