У меня есть две сущности 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
}
У меня есть форма, в которой я могу фильтровать людей по навыкам, каждый навык - это флажок, и мне нужно количество людей, обладающих этим навыком, вместе с меткой флажка.
Результат таков:
Я получил его, используя следующий собственный запрос:
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 вместо использования собственного запроса?






Фактически, при отображении сущностей с отношениями 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
}
Я понимаю проблему масштабируемости. Я прочитал немного больше об ассоциациях и хотел бы поделиться с вами Очень ленивая загрузка. Если это включено, вы можете использовать функцию подсчета (без фильтра), не загружая коллекцию. Хотя это зависит от того, насколько вы собираетесь использовать эту ассоциацию в своем приложении. Хорошего дня!
Спасибо за информацию :) Выглядит менее хакерским, чем мое решение! Ваше здоровье
Хорошо, я нашел решение:
$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
->filterв коллекции ArrayCollection требует сначала загрузить всю таблицу. Не масштабируется :-). Спасибо, в любом случае