Doctrine2错误地缓存了查询结果

时间:2017-02-02 10:47:56

标签: php caching doctrine-orm symfony dql

使用Symfony3的标准管理器查询构建器,我创建了这个查询:

$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();

这基本上选择" a",一个父实体," a2",一个子实体;他们俩都属于同一个班级。

当我使用2作为" id"运行此查询时参数,查询正确地为结果提供水合,返回一个结果,其中a.id = 1和a.id = 2.

之后,我立即重新运行查询设置3作为id;这次,结果应该是单一的,其中a.id = 1和a2.id = 3,但实际结果与id = 2时相同。
如果我只运行id = 3的查询,结果再次正确补充。

我最好的猜测是,doctrine正在缓存结果,并且由于某种原因,当我更改id时,它实际上并没有重新执行查询(尽管参数转储在id字段中显示正确的值);
在线搜索结果非常糟糕;我发现了有关此问题的旧(和修复)错误报告,并且对查询禁用的任何类型的缓存都没有带来任何改进。

我只能通过获取主实体来解决问题,然后手动查看子实体,但我真的很想知道那里有一种本地禁用缓存的方法,或者其他一些数据库端解决方案。

编辑: 我在测试环境中遇到过这个问题; 2个查询在2个不同(但连续)的函数调用中执行

1 个答案:

答案 0 :(得分:0)

您的问题不是某种查询缓存,而是对实体管理器如何工作的误解。

实体管理器跟踪从数据库加载的所有对象。当你的第二个查询的结果被水合时,它会看到这个特定的a实体已经被水合,因此它为你提供了第一个查询已经返回的完全相同的PHP对象实例($a_from_first_query === $a_from_second_query )。第二个结果中的rela2个对象会添加到$a->relazioniDa集合中,该集合已包含第一个查询中的rela2。在第二次查询后,$a->relazioniDa[0]->anagrafica_figlio->id将为2,$a->relazioniDa[1]->anagrafica_figlio->id将为3.这也称为增量水合。

为了防止这种情况,您可以通过调用$em->clear()清空两个查询之间的实体管理器。但是,您必须记住,这意味着在clear()之前检索到的任何实体的更改将 not 保存到下一个{{ 1}},因为实体管理器不再知道有关这些对象的任何信息。您也可以通过调用flush()从管理器中删除单个对象,但是如果您只分离父对象,则可能会导致问题,您可能必须从第一个查询中分离整个对象层次结构。