7

我将 Symfony 2 与 Doctrine 一起使用,并且我有两个实体加入了多对多关联。假设我有两个实体:User 和 Group,db 上的相关表是 users、groups 和 users_groups。

我想获得DQL 中人口最多的 10 个组,但我不知道在连接表 (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 吗?

更新(类):

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

3 回答 3

7

没有看到实际的类并不容易,但是通过猜测你有一个多对多的双向关系:

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

更新:

您不必使用双向关系,您可以反过来查询:

$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;";
于 2012-04-19T02:09:04.113 回答
1

对于那些想要使用 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也很有帮助。

于 2016-11-17T11:32:59.370 回答
0

要改进汤姆的答案,您可以使用 DQL 的HIDDEN关键字。这样,结果不包含无用的cnt列,并且不需要 Arvid 的array_map解决方案(这可以显着加快更大查询的结果)。OP 的问题是获得前 10 组,而不仅仅是他们的 ID。

它看起来像这样:

$query = 'SELECT g, HIDDEN COUNT(u.id) AS cnt FROM Entity\Group g LEFT JOIN g.users u ORDER BY cnt DESC';
$groups = $em->createQuery($query)->setMaxResults(10)->getResult();

另外,请注意使用LEFT JOINthat 确保不会解雇空组。

于 2020-06-29T07:14:56.587 回答