2012-04-16 2 views
7

Я использую Symfony 2 с Doctrine, и у меня есть две сущности, объединенные во многих отношениях. Предположим, у меня есть два объекта: Пользователь и группа, а связанные таблицы на db - это пользователи, группы и users_groups.DQL много для многих и счет

Я хочу получить 10 самых густонаселенных групп в DQL, но я не знаю синтаксиса для выполнения запросов в таблице соединений (users_groups). Я уже смотрел руководство по Doctrine, но я не нашел решение, я думаю, мне еще предстоит много узнать о DQL.

В простой SQL, который был бы:

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

Можете ли вы помочь мне перевести это DQL?

Update (классы):

/** 
* 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 ...*/ 
} 

ответ

6

Это не так просто, не видя реальные классы, но угадывая вас есть много-ко-многим двунаправленной связи:

$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(); 

UPDATE:

Вы не должны использовать, используя двунаправленную связь, вы можете Эри наоборот:

$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

спасибо, проблема в том, что у объекта Group нет ассоциации, называемой пользователями. Поэтому я получаю исключение: [Semantical Error] строка 0, col 72 рядом с GROUP BY g.id ': Ошибка: у класса Entity \ E_Group нет ассоциации с именами пользователей. Я обновил вопрос с помощью реальных классов. Должен ли я добавить атрибут $ users для объекта E_Group для двунаправленного отношения «многие ко многим»? –

+0

большое спасибо. Во всяком случае, у меня были двунаправленные отношения. Это был просто фиктивный запрос, чтобы понять, как он работает. еще раз спасибо –

0

Для тех, кто хочет построить запрос с Doctrine-х QueryBuilder вместо использования DQL непосредственно принимать это решение.

Обратите внимание, что моя проблема заключалась не в том, чтобы получить верхние группы пользователей, но технически проблема очень похожа на мою. Я работаю с сообщениями (например, статьи/сообщения в блогах) и тегами, которые добавляются к сообщениям. Мне нужно было определить список связанных сообщений (идентифицированных одними и теми же тегами). Этот список должен быть отсортирован по релевантности (те же самые теги, которые имеют более важная должность).

Это метод моего 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; 
} 

Спасибо @tom Imrei для вас решение. Также был очень полезен ответ #26549597.

 Смежные вопросы

  • Нет связанных вопросов^_^