【问题标题】:Doctrine: complicated select with two ManyToMany relationships教义:具有两个多对多关系的复杂选择
【发布时间】:2013-01-11 16:57:38
【问题描述】:

我需要在问题跟踪系统的表中查询多个问题,该系统通过复杂条件限制此查询:

问题(实体)被分组为类别(另一个实体)。人员(实体)是多个角色(第四个实体)的成员,这是一种多对多关系。最后,一个角色可以访问一个或多个类别,这是第二个多对多关系。

<?php

/**
 * @Entity
 * @Table(name="issue")
 */
class Issue
{
    /**
     * @ManyToOne(targetEntity="Category", fetch="EAGER")
     * @JoinColumn(name="category", referencedColumnName="id", onDelete="RESTRICT", nullable=false)
     */
    private $category;
    …
}

/**
 * @Entity
 * @Table(name="category")
 */
class Category
{
    /**
     * @ManyToMany(targetEntity="Role", mappedBy="categories")
     */
    private $roles;
    …
}

/**
 * @Entity
 * @Table(name="role")
 */
class Role
{
    /**
     * @ManyToMany(targetEntity="Person", mappedBy="roles")
     */
    private $persons;

    /**
     * @ManyToMany(targetEntity="Category", inversedBy="roles")
     * @JoinTable(name="role_has_access_on_category",
     *  joinColumns={@JoinColumn(name="role_id", referencedColumnName="id")},
     *  inverseJoinColumns={@JoinColumn(name="category_id", referencedColumnName="id")}
     * )
     */
    private $categories;
    …
}

/**
 * @Entity
 * @Table(name="person")
 */
class Person
{   
    /**
     * @ManyToMany(targetEntity="Role", inversedBy="persons")
     * @JoinTable(name="person_is_member_of_role",
     *  joinColumns={@JoinColumn(name="person_id", referencedColumnName="id")},
     *  inverseJoinColumns={@JoinColumn(name="role_id", referencedColumnName="id")})
     */
    private $roles;
    …
}

我已经把除了关系之外的所有字段都留下了,当然还有主键和更多的列……

我想检索属于具有给定主键的人可以通过其所属角色访问的类别的所有问题。

一开始我只是开始试验如何查询多对多关系,所以下面的代码与我的目标不太相似。 我终于找到了如何获取查询以检索一个多对多关系的另一端,因此我已经可以获取一个人所属的角色。但此查询不会获取角色有权访问的类别。

$qb = $this->em->createQueryBuilder();
$qb->select('person')
   ->addSelect('role')
   ->addSelect('category')
   ->from('Person', 'person')
   ->innerJoin('person.roles', 'role')
   ->innerJoin('role.categories', 'category');

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

$result 包含具有所有相关角色的人员数据,但包含一个空白的类别数组而不是实体。最终的查询当然会从问题方面开始,但现在我只想打通到另一边……

所以现在我想知道我是否必须扮演所有角色并循环访问它们以获取所有类别。没有更简单的教义方法吗?

顺便说一句,这就是我要使用的 SQL:

SELECT issue.* FROM person AS p, person_is_member_of_role AS pim, role_has_access_on_category AS rha, issue
WHERE
    p.id = pim.person_id AND
    pim.role_id = rha.role_id AND
    rha.category_id = todo.category AND
    p.id = ?;

我希望这一切都能以某种方式弄清楚,否则我会修改我的问题......

【问题讨论】:

    标签: doctrine-orm many-to-many query-builder


    【解决方案1】:

    您试图将所有连接条件都放在WHERE 子句中,从而使问题变得过于复杂。

    如果我正确理解了问题,则查询如下所示:

    SELECT
        i
    FROM
        Issue i
    JOIN
        i.category c
    JOIN
        c.roles r
    JOIN
        r.persons p
    WHERE
        p.id = :personId
    

    翻译成QueryBuilder API:

    $qb = $entityManager->createQueryBuilder();
    $issues = $qb
        ->select('i')
        ->from('Issue', 'i')
        ->innerJoin('i.category', 'c')
        ->innerJoin('c.roles', 'r')
        ->innerJoin('r.persons', 'p')
        ->andWhere($qb->expr()->eq('p.id', ':personId'))
        ->setParameter('personId', $personId)
        ->getQuery()
        ->getResult();
    

    此外,如果没有充分的理由使用 QueryBuilder,请考虑避免使用它。毕竟,它只是一个字符串生成器。

    【讨论】:

    • 太好了,非常感谢。特别是expr() 部分很有趣!你说我应该避免QueryBuilder,但在这种情况下这可能吗?我已经可以使用常规的findByX 方法。
    • 查询构建器只是组装一个字符串(如果您对它的实现感兴趣,可以查看Doctrine\ORM\QueryBuilder 的方法getQuery)。在大多数情况下,您可以只使用$em-&gt;createQuery($someDql)。只有当您有一个动态组装的查询时,查询构建器才会变得非常有用
    • 谢谢!我将尝试再次检查控制器并找到可以更改的地方。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-10-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多