Подтвердить что ты не робот

Doctrine2 загружает ассоциации "один ко многим" с режимом выборки, стремясь использовать слишком много SQL-запросов

Я загружаю список многих объектов.
Эти объекты имеют связь "один ко многим" с другими объектами.
Я хочу загрузить все эти другие объекты в одном 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();
    }
}

Метод UserRepository:: findUsersWithAddresses() выполняет 11 SQL-запросов.

Как я могу сообщить Doctrine использовать только один SQL-запрос для загрузки адресов?

Я использую:

  • symfony v2.0.9
  • doctrine-common 2.1.4
  • doctrine-dbal 2.1.5
  • доктрина 2.1.5
4b9b3361

Ответ 1

Текущая версия доктрины не поддерживает это.

запрос функции об этом в трееере проверки doctrine2.

Поэтому я надеюсь, что это будет реализовано в ближайшее время.

Ответ 2

Согласно вашей ссылке:

Вы можете пометить ассоциацию много-к-одному или один-к-одному как выбранную временно для пакетной выборки этих объектов с использованием запроса WHERE.. IN

Похоже, что текущая версия Doctrine, к сожалению, не поддерживает загрузку в коллекцию "один ко многим".

Эта страница, похоже, подтверждает это предположение:

@OneToMany

Обязательные атрибуты:

targetEntity: FQCN ссылочного целевого объекта. Может быть неквалифицированное имя класса, если оба класса находятся в одном пространстве имен. ВАЖНО: Никакой ведущей обратной косой черты!

Дополнительные атрибуты:

  • каскад: опция Cascade
  • orphanRemoval: Boolean, который указывает, если сироты, обратные объекты OneToOne, которые не связаны ни с одним обладающий экземпляром, должен быть удален Doctrine. По умолчанию false.
  • mappedBy: этот параметр указывает имя свойства в targetEntity это и есть собственная сторона этого отношения. Его обязательный атрибут для обратная сторона отношения.

Аннотация @OneToMany не содержит атрибута fetch, а не @OneToOne и @ManyToOne.

Забастовкa >


Update

Я только заметил, что вы действительно можете получить связанные объекты, используя явный LEFT JOIN в DQL:

SELECT u, a FROM User u
LEFT JOIN u.addresses a

Используйте LEFT JOIN, а не внутренний JOIN, или объекты с пустой коллекцией (User без каких-либо Address) будут опущены из набора результатов.

Обновление (2017)

Как указано GusDeCool и webDEVILopers в комментариях, атрибут fetch теперь поддерживается в @OneToMany. Вышеприведенный ответ устарел.

Ответ 3

У меня были точно такие же проблемы и обновился мой модуль доктрины в Zend Framework 2 до версии 2.5, и теперь все работает нормально. Вы можете проверить мой вопрос здесь