2

我有 3 个表 - 用户、区域和联系人。联系人可以属于用户或区域。一个用户可以属于很多领域。

我想提取属于用户的所有联系人(如数据库中特别定义的),以及与用户属于同一区域的所有联系人。

我能否重新审视我的数据库映射,以及我需要用 DQL 编写的查询以获得我想要的东西。我在我的数据库映射中做错了吗?

我绝对是一个 SQL 人,并且能够轻松地用纯 SQL 获取我想要的东西。在普通的 SQL 中,这就是我想要做的:

 select c.* from contact c LEFT JOIN user_area ua ON c.area_id=ua.area_id where (ua.user_id=XXX OR c.user_id=XXX);

用户

/**
 * @ORM\ManyToMany(targetEntity="area", inversedBy="areas")
 * @ORM\JoinTable(name="user_area",
 *      joinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id")},
 *      inverseJoinColumns={@ORM\JoinColumn(name="area_id", referencedColumnName="id")}
 *      )
 */
private $areas;

/**
 * @ORM\OneToMany(targetEntity="Contact", mappedBy="user")
 */
private $contacts;

接触

/**
 * @ORM\ManyToOne(targetEntity="Area")
 * @ORM\JoinColumn(name="area_id", referencedColumnName="id")
 */
private $area;

/**
 * @ORM\ManyToOne(targetEntity="User", inversedBy="Contacts")
 * @ORM\JoinColumn(name="user_id", referencedColumnName="id")
 */
private $user;

区域

/**
 * @ORM\ManyToMany(targetEntity="User", mappedBy="users")
 */
private $users;

/**
 * @ORM\OneToMany(targetEntity="Contact", mappedBy="area")
 */
private $contacts;

我遇到的主要问题是 DQL 确实希望您查询一个对象,而在 SQL 中查询用户/区域关系表以获得我想要的内容更容易。我试图编写一个查询,从联系人中提取区域,然后从联系人中提取用户,然后从区域中提取用户,但我收到一条错误消息,指出“用户”不是我的区域对象中定义的索引。再说一次,我是 Doctrine 新手,所以我可能做错了什么。

这是我在 Symfony 中的 User 对象中尝试的查询:

    $qb = $em->createQueryBuilder()
        ->addSelect('c')
        ->from('MyBundle:Contact', 'c')
        ->leftJoin('c.area', 'ca')
        ->leftJoin('c.user', 'cu')
        ->leftJoin('ca.users', 'cau')
        ->add('where', 'c.user = ?1 OR cau.id = ?1')
        ->add('orderBy', 'c.name')
        ->setParameter(1, $this->getId());
4

2 回答 2

1

有人应该为我提供先前的答案而扇我耳光。虽然它完成了工作,但我是绝对正确的,它没有被优化。使用该方法的查询需要 3 秒来回访问数据库(3 秒!)。显然,在我的世界里还有很多其他的事情正在发生,这些事情从性能作为完成这项工作的要求中消失了,但事情已经发生了变化。我设法将此查询分解为两个较小的(Doctrine 生成的)查询,每个查询可能需要 0.2 或 0.3 秒。

    $areas = $user->getAreas();

    $qb = $this->getEntityManager()->createQueryBuilder();
    $qb->select('c')
        ->from('MyBundle:Contact', 'c')
        ->where($qb->expr()->in('c.area', '?1'))
        ->orWhere('c.user = ?2')
        ->setParameter(1, $areas->toArray())
        ->setParameter(2, $user);
    $query = $qb->getQuery();
    $result = $query->getResult();
    return $result;

我必须调用的事实$user->getAreas()添加了一个数据库查询(如果 Doctrine 还没有该信息),但是使用 Query Builder 表达式的这段代码效果更好(0.3s 与 3s 是原始查询时间的 10%! )。

我认为我当时缺少的主要概念是查询生成器想要使用您的对象(实体)以及您在实体中定义的属性。来自强大的 SQL 背景,并且知道我希望 Doctrine 生成的特定 SQL 查询,我没有正确解决问题。

希望这个 8 个月大问题的更新对某人有所帮助!

于 2014-01-24T04:10:40.040 回答
0

所以事实证明你不能在 DQL 中获取对象的对象。我需要获取所有“区域”(“联系人”的对象),然后获取该区域的所有“用户”。

在 DQL 中,您可以指定多个“from()”辅助方法,这就是我完成工作所需要的。

$qb = $em->createQueryBuilder()
    ->addSelect('c')
    ->from('MyBundle:Contact', 'c')
    ->from('MyBundle:User', 'u')
    ->leftJoin('c.area', 'ca')
    ->leftJoin('c.user', 'cu')
    ->leftJoin('u.areas', 'ua')
    ->add('where', 'c.user = ?1 OR (ua.id=ca.id AND u.id = ?1')
    ->add('orderBy', 'c.name')
    ->setParameter(1, $this->getId());

从 Doctrine 生成的 SQL 似乎并没有特别优化,但它完成了工作。如果有人对让 Doctrine 更好地优化以下查询有任何想法,我很想听听意见。

SELECT m0_.id AS id0, m0_.name AS name1, m0_.email AS email2, m0_.media_area_id AS media_area_id3, m0_.user_id AS user_id4 FROM contact m0_ LEFT JOIN user u1_ ON m0_.user_id = u1_.id LEFT JOIN area m2_ ON m0_.area_id = m2_.id, user u3_ LEFT JOIN user_area u5_ ON u3_.id = u5_.user_id LEFT JOIN area m4_ ON m4_.id = u5_.area_id WHERE u1_.id = ? 或(m4_.id = m2_.id AND u3_.id = ?);

于 2013-05-04T18:51:54.213 回答