Выполнение COUNT (*) GROUP BY на основе отношения ManyToMany с использованием DQL?

У меня есть две сущности Person и Skill, где у Person может быть несколько навыков.

Person

/**
 * @ORM\Entity(repositoryClass = "App\Repository\PersonRepository")
 */
class Person
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type = "integer")
     */
    private $id;

    /**
     * @ORM\ManyToMany(targetEntity = "App\Entity\Skill", inversedBy = "people")
     */
    private $skills = [];

    // other fields and getters/setters
}

Skill

<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity(repositoryClass = "App\Repository\SkillRepository")
 */
class Skill
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type = "integer")
     */
    private $id;

    /**
     * @ORM\ManyToMany(targetEntity = "App\Entity\Person", mappedBy = "skills")
     */
    private $people = [];

    // other fields and getters/setters
}

У меня есть форма, в которой я могу фильтровать людей по навыкам, каждый навык - это флажок, и мне нужно количество людей, обладающих этим навыком, вместе с меткой флажка.

Результат таков:

Выполнение COUNT (*) GROUP BY на основе отношения ManyToMany с использованием DQL?

Я получил его, используя следующий собственный запрос:

SELECT s.id, COUNT(*) AS c
FROM skill s
JOIN person_skill ps   /* table required by the M2M relation between person and skill */
ON s.id = ps.skill_id
GROUP BY s.id

Как видите, мне требуется JOIN в таблице ManyToMany, чтобы получить эти подсчеты.

Как я мог сделать это с помощью DQL Doctrine вместо использования собственного запроса?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
0
0
402
2

Ответы 2

Фактически, при отображении сущностей с отношениями Doctrine использует настраиваемый объект с именем ArrayCollection.

Он имеет множество методов, таких как filter () и count ().

Вы можете добавить метод к своей сущности навыка, если хотите, чтобы он использовал метод count из ArrayCollection (people).

Чтобы убедиться, что вы правильно используете ArrayCollection, вам придется изменить свой класс Skill следующим образом:

class Skill
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type = "integer")
     */
    private $id;

    /**
     * @ORM\ManyToMany(targetEntity = "App\Entity\Person", mappedBy = "skills")
     */
    private $people; //<-- Removed the default array definition

    public function __construct()
    {
        $this->people = new ArrayCollection(); //Add this line in your constructor
    }

    public function countPeople()
    {
        return $this->people->count(); //Will return the number of people joined to the skill
    }

    // other fields and getters/setters
}
->filter в коллекции ArrayCollection требует сначала загрузить всю таблицу. Не масштабируется :-). Спасибо, в любом случае
Alain Tiemblo 25.10.2018 23:13

Я понимаю проблему масштабируемости. Я прочитал немного больше об ассоциациях и хотел бы поделиться с вами Очень ленивая загрузка. Если это включено, вы можете использовать функцию подсчета (без фильтра), не загружая коллекцию. Хотя это зависит от того, насколько вы собираетесь использовать эту ассоциацию в своем приложении. Хорошего дня!

Stefmachine 26.10.2018 02:40

Спасибо за информацию :) Выглядит менее хакерским, чем мое решение! Ваше здоровье

Alain Tiemblo 26.10.2018 21:14

Хорошо, я нашел решение:

$rows = $this->_em->createQueryBuilder('s')
                  ->select('s.id, COUNT(p.id) AS c')
                  ->from(Skill::class, 's')
                  ->join('s.people', 'p')
                  ->groupBy('s.id')
                  ->getQuery()
                  ->getArrayResult();

Он генерирует следующий запрос:

SELECT s0_.id AS id_0, COUNT(p1_.id) AS sclr_1 
FROM skill s0_ 
INNER JOIN person_skill p2_
ON s0_.id = p2_.skill_id 
INNER JOIN person p1_ 
ON p1_.id = p2_.person_id 
GROUP BY s0_.id

Другие вопросы по теме