我最近解决了查询ManyToMany
关系连接表的问题,解决方案与此答案相同,并且想知道它是如何工作的。假设我在groups
和team
之间有一个简单的ManyToMany
关系,这里会自动创建一个groups_team
表
组实体
/**
* Groups
*
* @ORM'Table(name="groups")
* @ORM'Entity(repositoryClass="AppBundle'Model'Repository'GroupsRepository")
*/
class Groups {
/**
* @ORM'ManyToMany(targetEntity="Team", inversedBy="group")
*/
protected $team;
public function __construct() {
$this->team = new ArrayCollection();
}
/**
* @var int
*
* @ORM'Column(name="id", type="integer")
* @ORM'Id
* @ORM'GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
*
* @ORM'Column(name="groupname", type="string", length=255)
*/
private $groupname;
//obligatory getters and setters :)
团队实体
/**
* Team
*
* @ORM'Table(name="team")
* @ORM'Entity(repositoryClass="AppBundle'Model'Repository'TeamRepository")
*/
class Team {
/**
* @ORM'ManyToMany(targetEntity="Groups", mappedBy="team")
*/
protected $group;
public function __construct(){
$this->group = new ArrayCollection();
}
/**
* @var int
*
* @ORM'Column(name="id", type="integer")
* @ORM'Id
* @ORM'GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
*
* @ORM'Column(name="teamname", type="string", length=255)
*/
private $team;
//[setters and getters here]
为了获得组中的所有团队,我必须查询groups_team
表.我会直接在MySQL中查询表,但在Symfony中我必须这样做
$groups = $em->getRepository("AppBundle'Model'Entity'Groups")->findBy(array('tournament' => $tournament->getId()));
//get all teams with group id in groups_team table
foreach ($groups as $group) {
$teamsingroup = $em->getRepository("AppBundle'Model'Entity'Team")->createQueryBuilder('o')
->innerJoin('o.group', 't')
->where('t.id = :group_id')
->setParameter('group_id', $group->getId())
->getQuery()->getResult();
echo "</b>".$group->getGroupname()."</b></br>";
foreach ($teamsingroup as $teamingroup) {
echo $teamingroup->getTeam()."</br>";
}
}
有人可以向我解释innerJoin
是如何工作的以及这背后的概念是什么,也许有一些文档可以了解这一点。 有没有更好的方法来用Symfony和Doctrine来做到这一点。
2 个实体之间使用ManyToMany
涉及第三个表,通常在此类关系中称为联结表,当您构建 DQL(学说查询)时,学说会根据您定义为注释的关系的性质自动联接联结表
$teamsingroup = $em->getRepository("AppBundle'Model'Entity'Team")
->createQueryBuilder('o')
->innerJoin('o.group', 't')
您正在Team
实体与Group
实体联接innerJoin('o.group')
部分中o
是团队实体的别名,o.group
是指Team
名为 group
的实体中定义的属性。
/**
* @ORM'ManyToMany(targetEntity="Groups", mappedBy="team")
*/
protected $group;
它为这种类型的关系原则定义了ManyToMany
注释,首先将团队表与联结表连接起来,然后将联结表与组表连接起来,生成的 SQL 将类似于
SELECT t.*
FROM teams t
INNER JOIN junction_table jt ON(t.id = jt.team_id)
INNER JOIN groups g ON(g.id = jt.group_id)
WHERE g.id = @group_id
另一件事与你为每个组获取团队的方式有关,你可以通过在循环中排除createQueryBuilder
部分来最小化你的代码,一旦你定义了 teams 属性ArrayCollection
即在每个组对象上$this->team = new ArrayCollection();
,你将获得与该特定组关联的团队集合通过在组对象上调用类似于以下代码的函数getTeam()
。
foreach ($groups as $group) {
$teamsingroup = $group->getTeam();
echo "</b>".$group->getGroupname()."</b></br>";
foreach ($teamsingroup as $teamingroup) {
echo $teamingroup->getTeam()."</br>";
}
}
我想它实际上是带有 INNER JOIN 的选择语句,使用键列将实体类定义为 mappedBy 或 inversedBy。你为什么不看看教义日志,看看原生SQL是由什么组成的?
如何让 Doctrine 在 Symfony2 中记录查询(stackoverflow)
http://vvv.tobiassjosten.net/symfony/logging-doctrine-queries-in-symfony2/(一些代码示例)
我不知道这背后的用户故事,但我也听说建议使用一对多关系而不是多对多,除非有充分的理由这样做,因为大多数情况可以通过重新考虑模型由一对多处理。