我有以下查询:
$query = $qb->select('p')
->from(get_class($page), 'p')
->innerJoin('p1.translations', 't')
->groupBy('p.id')
->addGroupBy('t.id')
->getQuery();
Doctrine返回上面的内容,如:
Page entity -> [translation 1, translation 2, translation 3]
但我希望结果如下:
Page entity 1 -> translation 1
Page entity 1 -> translation 2
Page entity 1 -> translation 3
有谁知道我怎么做到这一点?我想返回一个实体列表。
答案 0 :(得分:0)
首先,两个groupBy
都是完全多余的,假设您分组的两个id
字段是其各自表的主键。对于任何给定的(p.id, t.id)
组合,无论您是否进行分组,最多只能有一个结果。
其次,即使您加入了翻译表,也没有从中获取任何数据(t
中没有->select()
)。它只是出现这种方式,因为当你调用$page->getTranslations()
时,学说“神奇地”在背景中加载数据(假设你的getter被这样调用)。
第三,您的问题不在于groupBy
。在对查询结果进行保湿时,您完全误解了ORM实际上做了什么。从您的代码生成的SQL查询将实际上以您期望的方式返回结果,并且“Page entity 1”重复多次。
然而,现在是水合步骤。 Doctrine读取第一个结果行,构建“页面实体1”和“翻译1”实体,链接它们并将它们添加到它的内部实体注册表中。然后,对于第二个结果,Doctrine注意到它已经水化了“Page entity 1”对象并且(这是关键部分!)重用第一行中的相同对象,添加第二个翻译到现有对象的->translation
集合。即使您稍后在代码中以完全不同的查询再次阅读“页面实体1”,您仍然会再次获得相同的PHP对象。
这种行为是Doctrine所做的核心。基本上,数据库中的任何表行都将始终由PHP端的单个对象进行镜像,无论您多久或以何种方式从数据库中实际读取它。
总而言之,您的查询应如下所示:
$query = $qb->select('p, t')
->from(get_class($page), 'p')
->innerJoin('p.translations', 't')
->getQuery();
如果你真的需要遍历所有(p,t)组合,请使用嵌套循环:
foreach ($query->getResult() as $p) {
foreach ($p->getTranslations() as $t) {
// do something
}
}
编辑:如果您的关系是双向的,您也可以转过身来查询:
$query = $qb->select('t, p')
->from('My\Bundle\Entity\Translation', 't')
->innerJoin('t.page', 'p')
->getQuery();
现在在您的示例中,您实际上获得了3个结果,您可以在单个foreach()中迭代。您仍然只能获得一个“页面实体1”对象,查询结果中的所有翻译都指向它。