2016-07-04 3 views
1

Представьте себе следующую ситуацию. У вас есть книги:Doctrine: как активировать загрузку программно?

Book(bookId, authorId, title) 

и авторы:

Author(authorId, name) 

и каждая книга имеет (для простоты) одного автора.

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

$books = $this->getDoctrine() 
     ->getRepository('AppBundle:Book') 
     ->findAll(); 

foreach($books as $b) { 
    echo $b->getAuthor()->getName(); 
} 

Могу ли я программно спросить Доктрину загрузить авторов жадностью для этого конкретного запроса (не глобально с помощью конфигурации)?

Связанный:In Doctrine 2 can the Fetch Mode (Eager/Lazy etc.) be changed at runtime?

Связанный:http://doctrine-orm.readthedocs.io/projects/doctrine-orm/en/latest/tutorials/getting-started.html#list-of-bugs

+1

Самый простой способ - просто присоединиться к отношениям авторов, предпочтительно, создав собственный метод «findAllWithAuthors» в репозитории книг или аналогичный. Я написал ответ на аналогичный вопрос здесь http://stackoverflow.com/questions/36250248/symfony2-count-entity-fields-that-relate-to-another-entity/36253620#36253620 – JimL

+0

@JimL Omg ... это действительно так трудно сделать в Доктрине ?! –

+0

Я бы не назвал это тяжело. Наличие запросов в репозиториях считается лучшей практикой. Вы также можете просто создать запрос в контроллере. Стандартные простые методы (find, findby и т. Д.), Как правило, просто для того, чтобы вы начали. Очень немногие задерживаются в любой реальной логике приложения/домена. – JimL

ответ

1

Вы можете просто mark the association между книгами и авторами EAGER (по сравнению с неявной умолчанию LAZY) и доктрина всегда будет загружать эту конкретную ассоциацию фронт ,

Это может быть достигнуто путем добавления:

fetch=EAGER 

к отображению ассоциации.

Одним из возможных способов сделать это во время выполнения было бы создание Mapped Superclass. Суперкласс определял бы ваши отношения и другие части ваших ассоциаций (а не те отношения, которые вы пытаетесь настроить).

Затем, чтобы фактически использовать класс во время выполнения, вы могли бы создать две другие конкретные реализации: LazyBook и EagerBook. В зависимости от вашего сценария во время выполнения вы должны использовать один или другой из этих конкретных объектов реализации для создания своих ассоциаций.

Конечно, LazyBook бы определить свой Book ->Author ассоциации как LAZY один (явно или неявно) и EagerBook бы определить его как EAGER.

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

+1

Я спрашиваю конкретно о ** программном способе **, чтобы быть более гибким с запросами. Но спасибо за предложение этого варианта! –

+0

@DenisKulagin Хм, хорошо. Наверное, я не вижу разницы между «написанием его в программном обеспечении» и «программным». Неужели они не достигают той же цели? Или цель иметь единственную ассоциацию, которая * либо * LAZY, либо EAGER? Если это цель, я также не понимаю прецедента. – rockerest

+0

Да, разница в том, что в вашем случае вы не можете переключиться во время выполнения. На самом деле речь идет не только о вариантах использования, но и о гибкости. Мне нравится настраивать каждый запрос, поэтому он загружает точный объем данных. Не меньше, но не более того. –

-2

Одна очень важная вещь, чтобы понять здесь, что доктрина использует шаблон Mapper данных и не Активный шаблон записи (вы можете найти его в фреймворком, например):

Доктрины 2 - объектно-реляционный картограф (ORM) для PHP 5.4+, что обеспечивает прозрачную устойчивость для объектов PHP. Использует данные Картонный шаблон в сердце, направленный на полное разделение вашего домена/бизнес-логики от сохранения в реляционной базе данных системы управления.

Преимущество Доктрины для программиста заключается в возможности сосредоточиться на объектно-ориентированной бизнес-логике и беспокоиться о сохранении только как вторичной проблемой. Это не означает, что упорство преуменьшено Доктрина 2, однако мы считаем, что для объектно-ориентированного программирования существуют значительные преимущества , если сохраняемость и объекты поддерживаются отдельно.

http://doctrine-orm.readthedocs.io/projects/doctrine-orm/en/latest/tutorials/getting-started.html#what-is-doctrine

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

В свою очередь это означает, что вы можете сделать то же самое, что и с ActiveRecord, но теперь это делается только в другом месте. Давайте посмотрим на разницу:

В ActiveRecord на основе ORM (как Yii):

$books = Book::model()->with('author')->findAll(); 

В DataMapper основе ORM (как Symfony/Doctrine):

$books = $this->getDoctrine()->createQueryBuilder() 
    ->select(['b', 'a']) 
    ->from('AppBundle:Book', 'b') 
    ->join('b.author', a') 
    ->addSelect('a') 
    ->getQuery() 
    ->getResult(); 

Небольшой комментарий к более позднему. Запрос, который вы строите там, не SQL-запрос, а скорее DQL-запрос (язык-запрос-запрос, используемый в Doctrine).

Так присоединиться/addSelect здесь очень похожа на с на бывшем запросе просто говорит ORM движок, который вы хотели бы загрузить автор в том же запросе. Метаданные специфических отношений (например, имена столбцов для обеих базовых таблиц) по-прежнему определены там на уровне метаданных объектов.

Синтаксис (выберите, из, присоединиться) напоминает SQL с целью, но его не следует путать. Здесь, создавая запрос, вы управляете объектами ORM , а не столбцами/таблицами базы данных.

Смежные вопросы