doctrine2 загружает связи «один ко многим» с режимом извлечения, используя слишком много запросов SQL - PullRequest
18 голосов
/ 26 января 2012

Я загружаю список многих объектов.
Эти объекты имеют связь «один ко многим» с другими объектами.
Я хочу загрузить все эти другие объекты в одном запросе SQL (вместо одного запроса для каждого объекта в первом списке).

Как описано в документации doctrine2: http://www.doctrine -project.org / docs / orm / 2.1 / en / reference / dql-doctrine-query-language.html # временно-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
  • общее учение 2.1.4
  • доктрина-дбал 2.1.5
  • доктрина 2.1.5

Ответы [ 3 ]

8 голосов
/ 10 февраля 2012

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

В системе отслеживания проблем doctrine2 есть запрос функции .

Так что я надеюсь, что он скоро будет реализован.

6 голосов
/ 09 февраля 2012

По вашей ссылке:

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

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

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

@ OneToMany

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

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

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

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

Аннотация @OneToMany не имеет атрибута fetch, в отличие от @OneToOne и @ManyToOne.


Обновление

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

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

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

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

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

2 голосов
/ 15 мая 2014

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

...