doctrine2使用过多的SQL查询加载与获取模式一对多的关联

aus*_*usi 18 php doctrine symfony doctrine-orm

我正在加载许多实体的列表.
这些实体与其他实体具有一对多关联.
我想在一个SQL查询中加载所有这些其他实体(而不是对第一个列表中的每个实体进行一次查询).

如doctrine2文档中所述:http://www.doctrine-project.org/docs/orm/2.1/en/reference/dql-doctrine-query-language.html#temporarily-change-fetch-mode-in-dql这应该可以通过"EAGER"加载来实现.

但它没有按照描述的那样工作.

我的代码:

class User{
    /**
     * @ORM\OneToMany(targetEntity="Address", mappedBy="user", indexBy="id", fetch="EAGER")
     */
    protected $addresses;
    public function __construct(){
        $this->addresses = new ArrayCollection();
    }
}

class Address{
    /**
     * @ORM\ManyToOne(targetEntity="User", inversedBy="addresses")
     * @ORM\JoinColumns({
     *   @ORM\JoinColumn(name="UserId", referencedColumnName="id")
     * })
     */
    private $user;
}

class UserRepository{
    public function findUsersWithAddresses(){
        return $this->getEntityManager()
            ->createQuery('SELECT u FROM MyBundle:User u ORDER BY u.name ASC')
            ->setFetchMode('MyBundle\Entity\User', 'addresses', \Doctrine\ORM\Mapping\ClassMetadata::FETCH_EAGER)
            ->setMaxResults(10)
            ->getResult();
    }
}
Run Code Online (Sandbox Code Playgroud)

UserRepository :: findUsersWithAddresses()方法执行11个SQL查询.

如何告诉Doctrine只使用一个SQL查询来加载地址实体?

我在用:

  • symfony v2.0.9
  • 学说共同的2.1.4
  • 学说 - dbal 2.1.5
  • 学说2.1.5

aus*_*usi 8

当前版本的学说不支持这一点.

在doctrine2问题跟踪器中有关于此的功能请求.

所以我希望它能尽快实施.

  • 这已在Doctrine 2.5中实现 (3认同)
  • 在撰写这个答案时,"当前版本"是什么?我认为现在应该可以做到这一点吗?在DQL中使用地址`LEFT JOIN`. (2认同)

Ben*_*min 6

根据你的链接:

您可以标记临时获取的多对一或一对一关联,以使用WHERE .. IN查询批量获取这些实体

不幸的是,看起来当前版本的Doctrine不支持在一对多集合上进行预先加载.

这个页面似乎证实了这个假设:

@OneToMany

必需属性:

targetEntity:引用的目标实体的FQCN.如果两个类都在同一名称空间中,则可以是非限定类名.重要提示:没有领先的反斜杠!

可选属性:

  • 级联:级联选项
  • orphanRemoval:Boolean,指定是否应该通过Doctrine删除孤立,未连接到任何拥有实例的反向OneToOne实体.默认为false.
  • mappedBy:此选项指定targetEntity上的属性名称,该属性是此关系的拥有方.它是关系反面的必需属性.

@OneToMany批注不设有一个fetch属性,而不是@OneToOne@ManyToOne.


更新

我只是注意到你实际上可以使用LEFT JOINDQL中的显式来获取相关实体:

SELECT u, a FROM User u
LEFT JOIN u.addresses a
Run Code Online (Sandbox Code Playgroud)

使用a LEFT JOIN,而不是内部JOIN或具有空集合(User没有任何Address)的实体将从结果集中省略.

更新(2017年)

正如指出的GusDeCoolwebDEVILopers在评论中,fetch属性现在支持@OneToMany.上述答案现已过时.