使用Symfony3的标准管理器的查询生成器,我创建了这个查询:
$anagrafica = $em->createQueryBuilder()
->select("a, rel, a2")
->from("AppBundleEntityAnagraficaanagrafica", "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的查询,结果再次正确水合。
我的最佳猜测是,条令正在缓存结果,由于某种原因,当我更改id时,它实际上并没有重新执行查询(尽管参数转储在id字段中显示了正确的值)
在线搜索结果极差;我发现了关于这方面的旧(和修复的)错误报告,对查询禁用任何类型的缓存都没有带来任何改进。
我可以通过只获取主实体,然后手动查看子实体来解决这个问题,但我真的很想知道是否有办法在本地禁用缓存,或者其他类型的数据库端解决方案。
编辑:我在测试环境中遇到了这个问题;这两个查询在两个不同的(但连续的)函数调用中执行
您的问题不是某种查询缓存,而是对实体管理器工作方式的误解。
实体管理器跟踪已从数据库加载的所有对象。当第二个查询的结果被水合时,它会看到这个特定的a
实体已经被水合,因此它会为您提供第一个查询($a_from_first_query === $a_from_second_query
)已经返回的PHP对象实例。来自第二个结果的rel
和a2
对象被添加到$a->relazioniDa
集合,该集合已经包含来自第一个查询的rel
和a2
。第二次查询后,$a->relazioniDa[0]->anagrafica_figlio->id
将为2,$a->relazioniDa[1]->anagrafica_figlio->id
将为3。这也被称为增量水合作用。
为了防止这种情况,可以通过调用$em->clear()
来清空两个查询之间的实体管理器。不过,您必须记住,这意味着对在clear()
之前检索到的任何实体的更改将不会保存到下一个flush()
的数据库中,因为实体管理器不再知道这些对象的任何信息。您也可以通过调用$em->detach($entity)
从管理器中删除单个对象,但如果只分离父对象,则可能会导致问题,您可能必须从第一个查询中分离整个对象层次结构。