I have the following setup of related db tables:
Organization
+--------+---------+
| id | integer |
+--------+---------+
| name | string |
+--------+---------+
Division
+---------------+---------+
| id | integer |
+--------+----------------+
|organization_id| integer |
+---------------+---------+
| name | string |
+---------------+---------+
Subdivision
+---------------+---------+
| id | integer |
+--------+----------------+
| division_id | integer |
+---------------+---------+
| name | string |
+---------------+---------+
I'm using the Symfony2 with Doctrine2 ORM and FOSRestBundle.
Now I got confused with the Association Mapping.
When I require for a Organization, I would like to get the following
{
id: 1,
name: "organization1",
divisions: [
{
id: 1,
organization_id: 1,
name: "division1"
subdivisions: [
{
id: 1,
division_id: 1,
name: "subdivision1"
}
]
}
]
}
I figured out this one, and used One-To-Many bidirectional association mapping of Doctrine.
What gave me a headache, is the opposite direction of the relation. If I require for a specifig Subdivision, I would like to get the following:
{
id: 1,
division_id: 1,
name: "subdivision1",
division: {
id: 1,
organization_id: 1,
name: "division1"
organization: {
id: 1,
name: "organization"
}
}
]
}
But I get this:
{
id: 1,
division_id: 1,
name: "subdivision1",
division: {
id: 1,
organization_id: 1,
name: "division1",
organization: {
id: 1,
name: "organization1",
divisions: [/* ..list of all the other divisions.. */]
},
subdivisions: [/* ..list of all the other subdivisions.. */]
}
}
How can I remove the subdivisions and divisions from returned data using Doctrine?
Because I only need the subdivision, the division it belongs to and the organization the division belongs to. And listing all the tree takes a huge amount off data and time, while I don't need it all.
EDIT:
I'm using the following to retrieve the records (everythings works as espected):
$organization = $this
->getDoctrine()
->getRepository('MyTestBundle:Organization')
->find($id);
$organization = $this
->getDoctrine()
->getRepository('MyTestBundle:Organization')
->findAll();
And the opposite direction:
$subdivision = $this
->getDoctrine()
->getRepository('MyTestBundle:Subdivision')
->find($id);
This generates the following SQL:
SELECT t0.id AS id1, t0.division_id AS division_id2, t0.name AS name3, t0.division_id AS division_id4 FROM Subdivision t0 WHERE t0.id = ? ["11"] []
SELECT t0.id AS id1, t0.organization_id AS organization_id2, t0.name AS name3, t0.organization_id AS organization_id4 FROM Division t0 WHERE t0.id = ? [16] []
SELECT t0.id AS id1, t0.name AS name2 FROM Organization t0 WHERE t0.id = ? [15] []
SELECT t0.id AS id1, t0.organization_id AS organization_id2, t0.name AS name3, t0.organization_id AS organization_id4 FROM Division t0 WHERE t0.organization_id = ? [15] []
SELECT t0.id AS id1, t0.division_id AS division_id2, t0.name AS name3, t0.division_id AS division_id4 FROM Subdivision t0 WHERE t0.division_id = ? [15] []
SELECT t0.id AS id1, t0.division_id AS division_id2, t0.name AS name3, t0.division_id AS division_id4 FROM Subdivision t0 WHERE t0.division_id = ? [18] []
SELECT t0.id AS id1, t0.division_id AS division_id2, t0.name AS name3, t0.division_id AS division_id4 FROM Subdivision t0 WHERE t0.division_id = ? [19] []
SELECT t0.id AS id1, t0.division_id AS division_id2, t0.name AS name3, t0.division_id AS division_id4 FROM Subdivision t0 WHERE t0.division_id = ? [45] []
SELECT t0.id AS id1, t0.division_id AS division_id2, t0.name AS name3, t0.division_id AS division_id4 FROM Subdivision t0 WHERE t0.division_id = ? [49] []
SELECT t0.id AS id1, t0.division_id AS division_id2, t0.name AS name3, t0.division_id AS division_id4 FROM Subdivision t0 WHERE t0.division_id = ? [51] []
SELECT t0.id AS id1, t0.division_id AS division_id2, t0.name AS name3, t0.division_id AS division_id4 FROM Subdivision t0 WHERE t0.division_id = ? [56] []
SELECT t0.id AS id1, t0.division_id AS division_id2, t0.name AS name3, t0.division_id AS division_id4 FROM Subdivision t0 WHERE t0.division_id = ? [16] []
Replace $subdivision ... ->find($id)
with
$subdivision = $this
->getDoctrine()
->getRepository('MyTestBundle:Subdivision')
->createQueryBuilder('s')
->leftJoin('s.division', 'd')
->leftJoin('d.organization', 'o')
->where('s.id = :id')
->setParameter('id', $id)
->getQuery()
->getSingleResult();
This should already lower the count of request made by Doctrine. Of course the divisions
property of organization
will still exist, but the content is not automatically loaded with the first query. If you access the property via getDivisions()
the content will be loaded from the database. Its a feature of Doctrine to load necessary data without having the developer thinking about it. Of course its not the most performant way and you have to adopte this to your needs. Have a look at lazy loading and related topics.