Как получить сущность со всеми ее ассоциациями, используя EntityManager в Doctrine2? - PullRequest
6 голосов
/ 07 декабря 2011

У меня есть простая сущность со связями «многие ко многим» и «один ко многим».Мне известны «Соединения» для извлечения связанных ассоциаций, которые являются ручным решением для моей проблемы.

Как я могу получить сущность со всеми ее ассоциациями, используя EntityManager в Doctrine2?например:

$this->em
     ->getRepository('Entities\Patientprofile')
     ->findOneByuserid('555555557')
     ->fetchAllAssociations();

Ответы [ 4 ]

20 голосов
/ 18 апреля 2013

из http://doctrine -orm.readthedocs.org / en / latest / reference / dql-doctrine-query-language.html # временно-change-fetch-mode-in-dql

Вы можете временно установить нетерпеливый режим извлечения:

$query = $em->createQuery("SELECT u FROM MyProject\User u");
$query->setFetchMode("MyProject\User", "address", "EAGER");
$query->execute();

Если вы хотите динамически загружать все ассоциации с этим режимом выборки, вы можете использовать getAssociationMappings() метод Doctrine\ORM\Mapping\ClassMetadataInfo, передавая имя вашей сущности в качестве параметра конструктору ClassMetadataInfo, а затем перебирайте возвращаемый массив как $ assoc и вызов:

$query->setFetchMode("MyProject\User", $assoc, "EAGER");

Документ: ClassMetadataInfo # getAssociationMappings ()

12 голосов
/ 14 мая 2014

Doctrine2 setFetchMode не работает с "EAGER"

Я также пытался получить связанные сущности "охотно", используя setFetchMode в моем запросе, но следующее, похоже, не сработало:

$query->setFetchMode("MyProject\User", "address", "EAGER");

Когда я прыгнул в файлы , я обнаружил, что третий параметр $fetchMode должен быть целым числом . Константы определены в Doctrine \ ORM \ Mapping: ClassMetadataInfo. При передаче строки по умолчанию будет Mapping\ClassMetadata::FETCH_LAZY, потому что это условие if .

/**
 * 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;

/**
 * Specifies that an association is to be fetched lazy (on first access) and that
 * commands such as Collection#count, Collection#slice are issued directly against
 * the database if the collection is not yet initialized.
 */
const FETCH_EXTRA_LAZY = 4;

Таким образом, установка соответствующего целого числа решила проблему:

$query->setFetchMode("MyProject\User", "address", 3);

Или объявите класс use Doctrine\ORM\Mapping\ClassMetadata сверху, а затем используйте константу:

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

EDIT:

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

Согласно документации Doctrine существует 2 типа соединений:

  1. Обычные объединения : Используется для ограничения результатов и / или вычисления агрегированных значений.

  2. Извлечение объединений : В дополнение к использованию регулярных объединений: используется для извлечения связанных объектов и включения их в гидратированный результат запрос.

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

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

Пример такого пользовательского метода в репозитории сущностей Patientprofile из приведенного выше вопроса:

public function findPatientByIdWithAssociations($id)(
    // create a query builder for patient with alias 'p'
    $qb = $this->createQueryBuilder('p')
               ->where('p.id = :patient_id')
               ->addSelect('pd')
               ->leftJoin('p.documentation', 'pd')
               ->addSelect('pa')
               ->leftJoin('p.address', 'pa')
               ->setParameter('patient_id', $id);

    $query = $queryBuilder->getQuery();
    return $query->getSingleResult();
}

И теперь вы можете использовать свой собственный метод репозитория, чтобы получить пациента по идентификатору (например, «555555557»), включая связи с документацией пациента и адресом:

$repository = $this->em->getRepository('Entities\Patientprofile');
$patient = $repository->findPatientByIdWithAssociations('555555557');

Убедитесь, что вы используете addSelect и leftJoin для быстрой загрузки.

9 голосов
/ 08 декабря 2011

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

, но, если вам действительно нужно получить действительные классы ассоциации, вам нужноскажите в запросе, чтобы установить режим выборки в Doctrine \ ORM \ Mapping \ ClassMetadata :: FETCH_EAGER.Если вы используете аннотации, вы можете достичь этого с помощью:

например

/**
 * @ManyToMany(targetEntity="Item", fetch="EAGER")
 */
private $items;
5 голосов
/ 08 декабря 2011

Вы можете использовать DQL-запрос:

$query = $em->createQuery("SELECT p, f FROM Entities\\Patientprofile p JOIN p.Foo f WHERE p.id = ?1");
$query->setParameter(1, 321);
$patient = $query->getSingleResult();
...