Doctrine2 (Doctrine 2.1) активно загружается в Symfony2 - PullRequest
18 голосов
/ 12 января 2012

Скажем, у меня есть два объекта в моем проекте Symfony2: Category и Article (категория, содержащая много статей).

В моем CategoryRepository у меня есть этот метод:

findAllDummy(){
  return $this->createQueryBuilder('c')
              ->leftJoin('c.Articles a')
              ->getQuery()->getResult();
}

Если я хорошо помню, в Symfony1.4 (и соответствующей версии Doctrine) возвращенные объекты будут иметь свой атрибут «статьи», заполненный соответствующими Article объектами.Теперь в Symfony2 возвращаются объекты Proxy.

Так что, если я переберу статьи определенной категории, будет выполнено столько же запросов, сколько итераций.

foreach($category->getArticles() as $article){
  echo $article->getDoctrine()
               ->getRepository('')getTitle();
}

Я понимаю, что это Doctrine2.Режим ленивой загрузки по умолчанию 1.

Вопрос 1: как это лучшее решение?N запросов вместо 1.

Я попытался форсировать загрузку, выполнив следующее:

findAllDummy(){
  return $this->createQueryBuilder('c')
              ->leftJoin('c.articles a')
              ->getQuery()
              ->setFetchMode('Category', 'articles', 'EAGER')
              ->getResult();
}

Но результат остался прежним.

Вопрос 2: как заставить загружаться в Doctrine2?

Ответы [ 4 ]

18 голосов
/ 12 января 2012

Вы присоединяетесь к столу, но ничего не выбираете из него.Добавьте ->addSelect('a') к вашему построителю запросов.Чтобы понять разницу, рассмотрим два следующих SQL-запроса:

SELECT a.id, a.title
FROM article a 
JOIN category c ON a.category_id = c.id 
WHERE a.id = 123;

SELECT a.id, a.title, c.id, c.name 
FROM article a 
JOIN category c ON a.category_id = c.id 
WHERE a.id = 123;

Стремительное / ленивое соединение не имеет ничего общего с DQL-запросами.Он определяет, что должно быть загружено при использовании $articleRepository->find(123).

2 голосов
/ 27 августа 2015

В той части, где вы пытаетесь "принудительно загружать" , проблема может заключаться в том, что вы используете метод fetchMode с неверным типом переменной для аргумента $fetchMode.Вы передаете строку 'EAGER', но метод ожидает не строку, а целое число.

Метод ожидает константы из класса ClassMetadata:

/**
 * Specifies that an association is to be fetched when it is first accessed.
 */
const FETCH_LAZY = 2;

/**
 * Specifies that an association is to be fetched when the owner of the
 * association is fetched.
 */
const FETCH_EAGER = 3;

В документации Doctrineглава 14.7.6.6.Временно измените режим выборки в DQL , вы можете увидеть пример того, как его использовать:

$query->setFetchMode("MyProject\User", "address", \Doctrine\ORM\Mapping\ClassMetadata::FETCH_EAGER);

Так что передайте либо ссылку на константу, либо целое число, соответствующее режиму, который вы хотите использовать.

0 голосов
/ 06 июля 2017

Как сказано в доктринах , стремительная загрузка в этом случае не будет иметь никакого значения, потому что у вас есть отношение «один ко многим» между Category и Article.

Для отношений один-ко-многим изменение режима выборки на eager приведет к выполнению одного запроса для каждой загруженной корневой сущности.Это не дает улучшения по сравнению с режимом отложенной выборки, который также будет инициализировать ассоциации поочередно, когда к ним обращаются.нетерпеливая загрузка в DQL.Если у вас есть отношения один-к-одному или многие-к-одному, то стремительная загрузка решит проблему создания дополнительных запросов.Однако для решения вашей проблемы в этом случае вы должны использовать ->addSelect('a'), как упоминалось @Crozin.

0 голосов
/ 12 января 2012

Это лучшее решение, потому что объединение является гораздо более дорогим процессом, чем простой запрос. Хотя это может показаться неэффективным, это не большая трата и быстро становится более эффективным, когда вы не загружаете каждый бит каждого связанного объекта.

...