简体   繁体   中英

Doctrine2 incorrectly caching a query result

Using Symfony3's standard manager's query builder, i create this query:

$anagrafica = $em->createQueryBuilder()
    ->select("a, rel, a2")
    ->from("AppBundle\Entity\Anagrafica\anagrafica", "a")
        ->leftJoin("a.relazioniDa", "rel")
        ->leftJoin("rel.anagrafica_figlio", "a2")
    ->where("a.stato = :actStatus")
        ->andWhere("a = :anagrafica")
        ->andWhere($em->createQueryBuilder()->expr()->orX("a.id = :id", "a2.id = :id"))
    ->setParameter("anagrafica", $anagraficaInserente)
        ->setParameter("actStatus", $actStatus)
        ->setParameter("id", $id)
    ->getQuery()->getResult();

This basically selects "a", a parent entity, and "a2", a child entity; both of them belong to the same class.

When i run this query using 2 as the "id" parameter, the query correctly hydrates the results, returning me a single result where a.id = 1 and a.id =2.

Immediately after that, i re-run the query setting 3 as the id; this time, the result should be a single one, where a.id = 1 and a2.id = 3, but the actual result is the same as when id = 2.
If i only run the query where id = 3, the result is, once again, correctly hydrated.

My best guess is that doctrine is caching the result, and for some reason it doesn't actually re-execute the query when i change the id (despite the parameter dump showing the correct value in the id field);
Searching online yeld very poor results; i've found old (and fixed) bug reports about this, and any kind of cache disabling on the query didn't bring any improvement.

I can just work around the problem by only fetching the main entity, and then manually looking through the children ones, but i'd really like to know wheter there's a way to locally disable the cache, or some other kind of db-side solution.

EDIT: I'm having this issue in a test environnement; the 2 queries are executed in 2 different (yet consecutive) function calls

Your issue isn't with some sort of query caching, it's a misunderstanding about how the entity manager works.

The entity manager keeps track of all objects that have been loaded from the database. When the results of your second query are hydrated, it sees that this particular a entity has already been hydrated, so it gives you the very same PHP object instance that was already returned by the first query ( $a_from_first_query === $a_from_second_query ). The rel and a2 objects from the second result are added to the $a->relazioniDa collection, which already contains the rel and a2 from the first query. After the second query, $a->relazioniDa[0]->anagrafica_figlio->id will be 2 and $a->relazioniDa[1]->anagrafica_figlio->id will be 3. This is also called incremental hydration.

To prevent this, you can empty out the entity manager in between the two queries by calling $em->clear() . You have to keep in mind though, that this means that changes to any entities retrieved before the clear() will not be saved to the database on the next flush() , since the entity manager no longer knows anything about those objects. You can also remove a single object from the manager by calling $em->detach($entity) , however this might lead to problems if you only detach the parent object, you may have to detach the whole object hierarchy from your first query.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM