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