我正在使用symfony4。我有一个带有三个表的数据库结构,其中有两个一对多关系将它们相关联。例如:
房子 ->人 ->狗
每个房子都可以包含许多人,每个人都可以拥有许多狗。(我的数据库并不是真正关于房屋和狗,而是更改了实际的桌子名称以保护无辜者。)使用学说实体,i当然具有诸如$house->getPersons()
和$person->getDogs()
之类的功能。但是,实现诸如$house->getDogs()
之类的函数的正确方法是什么?我可以提出几种解决方案,但它们似乎都对我来说是一种"好"解决方案:
-
我可以简单地添加一个与狗有关的一对多关系。但是,这与普通数据库结构的基本规则之一:没有冗余数据。关系屋 -> person->狗已经在数据库中表达了住在另一个(这不是我想要的)。
-
我只能做
之类的事情foreach($house->getPersons() as $person){ $person->getDogs(); // Do something with each dog ... }
这不是很好的优化,因为我会为每个人开一个单独的查询 - 可能是很多查询 - 当我可以轻松地与一对夫妇加入时,我可以轻松地运行一个查询。
-
我可以在房屋实体内使用housereerposoritor或查询构建器来运行自定义查询。据我了解,这是在Symfony上皱眉的。我们通常不想要任何DQL或在实体类中使用存储库,正确吗?
-
我可以在服务/控制器内使用housereerposoritor运行自定义查询。这将是一种简单的方法,但感觉有些不贵。尽管如此,我感觉这可能是"正确的"方式。
总结一下:我有一种感觉应该能够以某种方式将这种相当简单的双重加入在我的实体中,而不必到达存储库级别即可获取此数据。需要明确的是,我不是在问如何编写DQL加入,我问的是正确的位置,或者是否有一些聪明的符合方式可以使用标准或类似的内容来执行此操作。
<。如果您想致电$house->getDogs()
,则可以在您的房屋实体中添加一种方法。
public function getDogs()
{
/** @var DoctrineCommonCollectionsArrayCollection */
$dogs = new ArrayCollection();
if ($persons = $this->getPersons()) {
foreach($persons as $person) {
if ($d = $person->getDogs()) {
$dogs->add($d);
}
}
}
return $dogs;
}
以每个人的方式迭代它是完全有效的。如果您希望最大程度地减少数据库的命中,则可以使用一些联接语句来"预先选择"您所需的所有内容,一次旅行到DB。使用此处显示的技术,请尝试以下代码。
假设一对一与许多关系的人 ->人 ->人与许多关系的人 ->狗,然后在您的housereerepository中使用一种方法,将所有相关数据拉到单个查询中,包括所有相关人员和狗(S)。
class HouseRepository extends ServiceEntityRepository
{
$qb = $this->createQueryBuilder('house')
->leftJoin('house.persons', 'persons')
->addSelect('persons')
->leftJoin('persons.dogs', 'dogs')
->addSelect('dogs')
->getQuery()->getResult();
}
当然,这是未经测试的,我怀疑返回的数据结构将是如此杂乱,即使它有效,您的代码也可能很难处理。