Особенности PARTIAL DQL запросов в Doctrine
// 28 декабря, 2017 // Doctrine 2, PHP
Иногда у вас может возникнуть ситуация, когда вроде бы при нормальном DQL-запросе объект почему-то грузится не весь. Ну т.е. запрос проходит стадию преобразования из DQL в SQL, выполняется, потом обратно идёт гидрация в объект, а части данных то и нет — отсутствуют некоторые поля, котоыре есть а базе данных. Вы конечно пробуете отключить все кэши, сбрасываете их по 10 раз, а толку ноль. Разгадка тут проста. Если в течении одного HTTP-запроса вы используете PARTIAL-запрос, то потом для всех следующих запросов в которые попадает этот объект по IDENITY-MAP он уже не грузится из БД, а берется из неё.
Пример
Пусть у нас есть модель User с полями id, username, name.
Грузим её через QueryBuilder.
$qb = $this->em->createQueryBuilder(); $qb->select('PARTIAL u.{id, username}') ->from(User::class, 'u') ->where('u.id = :id') ->setParameter(':id', $id); $user = $qb->getQuery()->getResult();
Потом мы в другом куске кода захотели загрузить юзера полностью.
$qb->select('u') ->from(User::class, 'u') ->where('u.id = :id') ->setParameter(':id', $id); $user = $qb->getQuery()->getResult();
При это окажется, что user->getName равен null. В такой ситуации есть два выхода 🙂 Первый — делать полную перезагрузку модели из БД.
$this->em->refresh($user);
Но если таких моделей много, это чревато большой нагрузкой на базу. Второй вариант — использовать специальный HINT, который скажет Doctrine, что надо обращаться к базе, вместо использования IDENTITY MAP.
$user = $qb->getQuery()->setHint(Query::HINT_REFRESH, true)->getResult();
Спасибо!
Если вам помогла статья, или вы хотите поддержать мои исследования и блог - вот лучший способ сделать это: