Join from inversed side

时间:2016-04-07 10:35:51

标签: symfony doctrine-orm dql

given the two following intities:

<?php
    /**
     * User
     * @ORM\Entity()
     */
    class User implements AdvancedUserInterface, \Serializable, EncoderAwareInterface
    {
        /**
         * @var Vip
         * @ORM\OneToOne(targetEntity="Vip", mappedBy="user", fetch="EAGER")
         */
        protected $vip;

        // …

<?php
    /**
     * Vip
     * @ORM\Entity()
     */
    class Vip
    {
        /**
         * @ORM\id @ORM\OneToOne(targetEntity="User", inversedBy="vip", fetch="EAGER")
         * @ORM\JoinColumn(name="user_id", referencedColumnName="id", nullable=false)
         */
        protected $user;

        // …

SHORT :
How can I do this SQL in DQL given above entities:
SELECT u.firstName, v.foo FROM User join Vip v ON v.user_id = u.id

In other words how can I retrieve 10 first users ( with their VIP infos if it exists), using DQL join in such a way that only one SQL query will be generated by Doctrine. Is that possible ?


Long story:
The owning side is the Vip entity because it holds the reference/foreign key to a User underneath in the database.

I am trying to retrieve all User with their Vip datas.
Using the knplabs/knp-paginator-bundle, I first set up a simple query:

$dql = "SELECT u, p FROM AppBundle:User u;

In spite of enforcing the fetch attribute as « EAGER », Vip infos where not part of the initial query. As a consequence, calling getter getVip() on each iteration from inside the twig for in loop like

{% for user in pagination %}
    {% if user.getVip() %}
        <span class="label label-warning">V.I.P</span>
    {% endif %}
{{% endfor %}}

.. caused a query to be issued on each iteration !

The Symfony dev bar shows 6 queries:

paginator OneToOne relationship queries issued by Doctrine

DQL documentation and says that one can use JOIN keyword. So my query became:
$dql = "SELECT u, v FROM AppBundle:User u JOIN u.vip v;

But now I get this error:

Warning: spl_object_hash() expects parameter 1 to be object, null given

Here I'm stuck, wondering how I could fetch Vip datas (or null) along with User datas, in a single query.

1 个答案:

答案 0 :(得分:1)

  

换句话说,如何检索10个第一个用户(使用他们的VIP)   如果它存在的信息),使用DQL连接只有一个SQL的方式   查询将由Doctrine生成。这可能吗?

您应该使用select子句初始化所有相关实体,以避免在访问相关对象时出现其他查询。

$repository = $em->getRepository(User::class);

$users = $repository->createQueryBuilder('u')
        ->addSelect('v') // Initialize Vip's
        ->join('u.vip', 'v')
        ->getQuery()
        ->setMaxResults(10)
        ->getResult();