7

私はDoctrineでSymfony2を使用しており、2つのエンティティが多対多の関連付けに参加しています。UserとGroupの2つのエンティティがあり、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

QueryBuilderDQL を直接使用するのではなく、Doctrine でクエリを作成したい場合は、このソリューションを使用してください。

私の問題は上位のユーザー グループを取得することではありませんでしたが、技術的には問題は私のものとかなり似ていることに注意してください。投稿 (記事/ブログ投稿など) と投稿に追加されるタグを操作します。関連する投稿のリストを特定する必要がありました (同じタグで識別されます)。そのリストは関連性でソートする必要がありました (別の投稿に同じタグが多いほど関連性が高くなります)。

これは私の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 に答える