Doctrine DQL JOIN

4

我使用Doctrine 2映射了以下实体:

class Zone
{
    /**
     * @ManyToOne(targetEntity="Zone", inversedBy="children")
     * @var Zone
     */
    protected $parent;

    /**
     * @OneToMany(targetEntity="Zone", mappedBy="parent")
     * @var Zone[]
     */
    protected $children;

    /**
     * @ManyToMany(targetEntity="Zone")
     * @var Zone[]
     */
    protected $descendants;
}

class Restaurant
{
    /**
     * @ManyToOne(targetEntity="Zone")
     * @var Zone
     */
    protected $zone;
}

基本上,一个区域有一个父级,因此也有子级。由于子级可能也有自己的子级,因此每个区域都会保留其所有后代的列表。

每个餐厅都被分配到一个区域。

我想做的是执行一个 DQL JOIN 来返回特定区域(包括其所有后代)中的所有餐厅。

如果我必须在普通 SQL 中执行此操作,我会写:

SELECT r.* from Zone z
JOIN ZoneDescendant d ON d.zoneId = z.id
JOIN Restaurant r ON r.zoneId = d.descendantId
WHERE z.id = ?;

使用Doctrine DQL是否可以实现这一点,而不必在Zone上添加$restaurants属性,并且不必使域模型变得复杂化?
2个回答

10

好的,我最终找到了一种仅使用JOINs的方法来完成它(在MySQL上显着更快):

SELECT r
FROM Restaurant r,
     Zone z
JOIN z.descendants d
WHERE r.zone = d
AND z = ?1;

1
是的,这样好多了,很高兴你找到了更好的解决方案!好主意 :) - Diego

1

我能想到的在单个DQL查询中完成这个任务的唯一方法是使用子查询:

SELECT r FROM Restaurant r WHERE r.zone IN (SELECT zc.id FROM r.zone z JOIN z.children zc WHERE z.id = :zoneId) OR r.zone = :zoneId

这个想法可行,谢谢!但是我对性能有一些担忧。我正在运行MySQL 5.6.3 m6,它仍然不会将这些子查询重写为JOIN,并且在面对这些查询时会显著减慢速度。我认为最有效的解决方案可能是创建一个ZoneRestaurants视图来执行适当的JOIN,然后在Zone中包含一个“虚假”的(在类中未使用的)$restaurants属性,并将此属性映射为@ManyToMany,使用ZoneRestaurants视图作为连接表。 - BenMorel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接