As the title states,
I would like to run 1 query to get results from a table with the count of their respective relationships.
Lets say I have a Person
entity with a OneToMany relationship with a Friend
entity
The Person entity might look something like the following:
class Person
{
/**
* @ORM\OneToMany(...)
*/
protected $friends;
public function __construct()
{
$this->friends = new ArrayCollection();
}
...
}
A classic SQL solution to what I want to achieve might look like the following:
SELECT p.*, COUNT(f.id) as friendsCount
FROM Persons p
LEFT JOIN Friends f
ON f.person_id = p.id
GROUP BY p.id
Now I am wondering if this could be done in DQL as well and storing the count value into the Person
Entity
Lets say I expand the Person
entity like: (Keep in mind this is just an idea)
class Person
{
/**
* @ORM\OneToMany(...)
*/
protected $friends;
protected $friendsCount;
public method __construct()
{
$this->friends = new ArrayCollection();
}
...
public function getFriendsCount()
{
return $this->friendsCount;
}
}
Now I am having trouble finding how I could populate the count value in the entity from DQL:
SELECT p, /* What comes here ? */
FROM AppBundle\Entity\Person p
LEFT JOIN p.friends f
GROUP BY p.id
PS: I do know I could just do:
$person->getFriends()->count();
And even mark it as extra lazy to get the count result.
I just though this count relationships example demonstrated well what I am trying to do.
(Which is populating the entity's non @ORM\Column
properties from dql)
Is this possible with Doctrine ?
Is this breaking some solid principles ? (SRP ?)
Cookie for your thoughs ;)
You probably just want to select the count as you need it, as described above with $person->getFriends()->count();
. However, you can select both an object and a count at the same time - see these Doctrine DQL examples, there is one very similar to what you are doing:
SELECT p, COUNT(p.friends)
FROM AppBundle\Entity\Person p
LEFT JOIN p.friends f
GROUP BY p.id
What should be returned back is an array of arrays with the object and count, like so:
[
[Person, int],
[Person, int],
...,
]
Your best bet would be to make that a Repository call on your PersonRepository
, something like findPersonsWithFriendCount()
, which would look like:
public function findPersonsWithFriendCount()
{
$persons = array();
$query = $this->_em->createQuery('
SELECT p, COUNT(p.friends)
FROM AppBundle\Entity\Person p
LEFT JOIN p.friends f
GROUP BY p.id
');
$results = $query->getResult();
foreach ($results as $result) {
$person = $result[0];
$person->setFriendsCount($result[1]);
$persons[] = $person;
}
return $persons;
}
Keep in mind you'd need to add a setFriendsCount()
function on your Person
object. You could also write a native SQL query and use result set mapping to automatically map your raw result's columns to your entity fields.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With