单个Doctrine连接表中的多个关系

时间:2017-09-15 13:51:19

标签: php mysql symfony doctrine-orm doctrine

我有一个通过单个(!)连接表与多个其他表相关的表 这是一个粗略的草图:

pupils_table  (master table)
---
id  name

teachers_table  (related table 1)
---
id  first_name  last_name  ...

courses_table  (related table 2)
---
id  start_date  end_date  ...

join_table  (relates master to both (!) related tables)
---
id  master_id  teacher_id  course_id

使用他们的老师和课程获得完整学生记录的标准SQL查询将是:

select p.*, t.*, c.* from pupils_table p 
left join join_table jt on jt.master_id = p.id
inner join teachers_table t on t.id = jt.teacher_id
inner join courses_table  c on c.id = jt.courses_id
;

但是我很难使用Doctrine的关系映射和QueryBuilder创建这样的查询。我找到的所有示例都使用将主表与一个相关表关联的连接表。

以下是我在实体中尝试的内容,如果我的主人:

/**
* @ORM\Table(name="pupils_table")
*/
class Pupils
{
    /**
     * @ORM\Column(type="integer")
     * @ORM\Id()
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\ManyToMany(targetEntity="AppBundle\Entity\Teachers")
     * @ORM\JoinTable(name="join_table",
     *     joinColumns={@ORM\JoinColumn(name="master_id", referencedColumnName="id")},
     *     inverseJoinColumns={@ORM\JoinColumn(name="teacher_id", referencedColumnName="id")}     * )
     */
    private $teachers;

    /**
     * @ORM\ManyToMany(targetEntity="AppBundle\Entity\Courses")
     * @ORM\JoinTable(name="join_table",
     *     joinColumns={@ORM\JoinColumn(name="master_id", referencedColumnName="id")},
     *     inverseJoinColumns={@ORM\JoinColumn(name="course_id", referencedColumnName="id")}     * )
     */
    private $courses;

    ...

到目前为止,我没有在教师和课程实体中引入任何特殊关系。

我的查询构建如下:

    $qb->select('p', 't', 'c')
        ->from('AppBundle:Pupils', 'p')
        ->innerJoin('p.teachers', 't')
        ->innerJoin('p.courses', 'c')
    ;

    $res = $qb->getQuery()->getResult();

结果是一个带有错误的内部连接序列的SQL查询,结果没有正确地嵌套相关数据(这可以用于这个SQL):

SELECT ... FROM pupils_table c0_
INNER JOIN join_table c3_ ON c0_.id = c3_.master_id 
INNER JOIN teachers_table c1_ ON c1_.id = c3_.teacher_id 
INNER JOIN join_table c4_ ON c0_.id = c4_.master_id 
INNER JOIN courses_table c2_ ON c2_.id = c4_.course_id 

如您所见,内部联接之前没有左联接,并且join_table也连接了两次。我知道我没有在我的QueryBuilder命令中明确添加左连接,但是如果连接表只在DocBlock注释中提到并且没有自己的实体(这是文档告诉我的),我该怎么办?

1 个答案:

答案 0 :(得分:0)

为了实现这种类型的映射,我会选择将保存对这3个实体的引用的结点实体,并且该结构将生成您在帖子中提到的正确的SQL。以下是我们如何创建和关联联结实体的解释

首先不要直接链接这3个实体,而是用以下方式将您的交汇点实体链接到这3个

PupilTeacherCourseHasMany ---ManyToOne---> Pupils
PupilTeacherCourseHasMany ---ManyToOne---> Teachers
PupilTeacherCourseHasMany ---ManyToOne---> Courses

Pupils ---OneToMany---> PupilTeacherCourseHasMany
Teachers ---OneToMany---> PupilTeacherCourseHasMany
Courses---OneToMany---> PupilTeacherCourseHasMany

小学生课程

/**
 * Pupils
 * @ORM\Table(name="pupils")
 * @ORM\Entity
 */
class Pupils
{
    /**
     * @ORM\OneToMany(targetEntity="NameSpace\YourBundle\Entity\PupilTeacherCourseHasMany", mappedBy="pupils",cascade={"your options"} )
     */
    protected $pupilTeacherCourseHasMany;

}

教师班级

/**
 * Teachers
 * @ORM\Table(name="teachers")
 * @ORM\Entity
 */
class Teachers
{
    /**
     * @ORM\OneToMany(targetEntity="NameSpace\YourBundle\Entity\PupilTeacherCourseHasMany", mappedBy="teachers",cascade={"your options"} )
     */
    protected $pupilTeacherCourseHasMany;

}

课程班级

/**
 * Courses
 * @ORM\Table(name="courses")
 * @ORM\Entity
 */
class Courses
{
    /**
     * @ORM\OneToMany(targetEntity="NameSpace\YourBundle\Entity\PupilTeacherCourseHasMany", mappedBy="courses",cascade={"your options"} )
     */
    protected $pupilTeacherCourseHasMany;

}

<强> PupilTeacherCourseHasMany

/**
 * PupilTeacherCourseHasMany
 * @ORM\Table(name="pupilteachercoursehasmany")
 * @ORM\Entity
 */
class PupilTeacherCourseHasMany
{
    /**
     * @ORM\ManyToOne(targetEntity="NameSpace\YourBundle\Entity\Pupils", cascade={"your options"})
     * @ORM\JoinColumn(name="pupil_id", referencedColumnName="id")
     */
    protected $pupils;

    /**
     * @ORM\ManyToOne(targetEntity="NameSpace\YourBundle\Entity\Teachers", cascade={"your options"})
     * @ORM\JoinColumn(name="teacher_id", referencedColumnName="id")
     */
    protected $teachers;


    /**
     * @ORM\ManyToOne(targetEntity="NameSpace\YourBundle\Entity\Courses", cascade={"your options"})
     * @ORM\JoinColumn(name="course_id", referencedColumnName="id")
     */
    protected $courses;
}

现在要获取所有细节,你的学说查询将是一些像

$qb->select('p', 't', 'c')
    ->from('AppBundle:Pupils', 'p')
    ->leftJoin('AppBundle:PupilTeacherCourseHasMany ptc')
    ->innerJoin('ptc.teachers', 't')
    ->innerJoin('ptc.courses', 'c')
;
$res = $qb->getQuery()->getResult();

For reference see my another answer