Что такое прокси в доктрине 2? - PullRequest
110 голосов
/ 07 февраля 2011

Я только что закончил читать всю документацию по Doctrine 2, я запустил свою собственную песочницу, я понял большинство принципов, но все еще есть вопрос, и я не смог найти никакого полного объяснения в документе.

  1. Что такое Proxy классы?
  2. Когда я должен использовать их поверх сущностей?

Насколько я понимаю, прокси-классы добавляют слой, чтобы позволить вам добавить некоторые другие функции к вашим сущностям, но зачем использовать проксивместо реализации самих методов в классе сущности?

Ответы [ 2 ]

159 голосов
/ 07 февраля 2011

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

@Entity
class User {
     @Column protected $id;
     @Column protected $username;
     @Column protected $firstname;
     @Column protected $lastname;

     // bunch of setters/getters here
}

DQL query:

SELECT u.id, u.username FROM Entity\User u WHERE u.id = :id

Как видите, этот запрос не возвращает свойства firstname и lastname, поэтому вы не можете создать объект User.Создание неполного объекта может привести к непредвиденным ошибкам.

Именно поэтому Doctrine создаст UserProxy объект, поддерживающий отложенную загрузку.Когда вы попытаетесь получить доступ к свойству firstname (которое не загружено), оно сначала загрузит это значение из базы данных.


Я имею в виду, почему я должен использовать прокси?

Вы всегда должны писать свой код, как если бы вы вообще не использовали прокси-объекты.Они могут рассматриваться как внутренние объекты, используемые Doctrine.

Почему ленивая загрузка не может быть реализована в самом Entitiy?

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

Можете ли вы предоставить мне вариант использования?

Вы отображаете список последних 25 статей, и вы хотитеотображать детали первого.Каждый из них содержит большое количество текста, поэтому получение всех этих данных будет пустой тратой памяти.Вот почему вы не извлекаете ненужные данные.

SELECT a.title, a.createdAt
FROM Entity\Article a
ORDER BY a.createdAt DESC
LIMIT 25

$isFirst = true;
foreach ($articles as $article) {
    echo $article->getTitle();
    echo $article->getCreatedAt();

    if ($isFirst) {
        echo $article->getContent(); // Article::content is not loaded so it is transparently loaded 
                                     // for this single article.

        $isFirst = false;
    }
}

ОБНОВЛЕНИЕ

В разделе комментариев ниже приведена неверная информация о различиях между прокси-объектами и частичными объектами.См. Ответы @Kontrollfreak для более подробной информации: https://stackoverflow.com/a/17787070/252591

77 голосов
/ 22 июля 2013

Прокси

Прокси Doctrine - это просто оболочка, которая расширяет класс сущностей для обеспечения отложенной загрузки для него.

По умолчанию, когда вы запрашиваете Entity Manager для сущности, которая связанас другой сущностью, связанная сущность не будет загружена из базы данных, но будет помещена в прокси-объект.Когда ваше приложение затем запрашивает свойство или вызывает метод этой прокси-сущности, Doctrine будет загружать сущность из базы данных (кроме случаев, когда вы запрашиваете идентификатор, который всегда известен прокси-серверу).

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

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


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

К сожалению, ответ Крозина содержит дезинформацию.

Если вы выполните запрос DQL, например

SELECT u.id, u.username FROM Entity\User u WHERE u.id = :id

, вы не получите (прокси) объект-сущность, но ассоциативный массив.Поэтому невозможно лениво загружать какие-либо дополнительные свойства.

Имея это в виду, можно прийти к выводу, что пример варианта использования также не будет работать.Чтобы получить доступ к $article как объекту, нужно изменить DQL на что-то подобное:

SELECT a FROM Entity\Article a ORDER BY a.createdAt DESC LIMIT 25

И возвращаемое getContent() свойство должно быть ассоциацией, чтобы не загружатьсвойства содержимого всех 25 сущностей.


Частичные объекты

Если вы хотите частично загрузить свойства сущностей, которые не являются ассоциациями, вы должны явно указать эту доктрину:

SELECT partial u.{id, username} FROM Entity\User u WHERE u.id = :id

Это дает вам частично загруженный объект сущности.

Но имейте в виду, что частичные объекты не являются прокси!Ленивая загрузка не относится к ним.Поэтому использование частичных объектов, как правило, опасно, и его следует избегать.Подробнее: Частичные объекты - Доктрина 2 Документация ORM 2

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...