Доктрина2 слишком часто вызывает префлаш (?)
Я только что заметил странное поведение системы событий Доктрины. В документации я прочитал о событии preFlush
:
preFlush
вызывается вEntityManager#flush()
перед чем-либо еще
Звучит неплохо. Но когда я создал подписчика событий, я увидел, что что-то не так - preFlush
произошло дважды, в то время как onFlush
и postFlush
только один раз (я предполагал, что preFlush
также происходит один раз).
Что интересно, preFlush
вызывается каждый раз, когда UnitOfWork
вычисляет набор изменений - равно числу в настоящее время управляемые организации.
Вот краткий пример (Доктрина 2.4, я не использую Symfony):
// event subscriber class:
class Subscriber implements EventSubscriber {
public function getSubscribedEvents() {
return array(Events::preFlush, Events::onFlush, Events::postFlush);
}
public function preFlush() {
echo '********** PRE FLUSH ***********' . "\n";
}
public function onFlush() {
echo '********** ON FLUSH ***********' . "\n";
}
public function postFlush() {
echo '********** POST FLUSH ***********' . "\n";
}
}
// test:
$em->getEventManager()->addEventSubscriber(new Subscriber());
for($i = 0; $i < 5; $i++) {
echo 'i = ' . $i . "\n";
$u = new Unit(); // Unit is sample entity - very simple one with no associations
$u->setName('unit');
$u->setSymbol('u');
$em->persist($u);
$em->flush();
}
Выдает результат:
i = 0
********** PRE FLUSH ***********
********** PRE FLUSH ***********
********** ON FLUSH ***********
********** POST FLUSH ***********
i = 1
********** PRE FLUSH ***********
********** PRE FLUSH ***********
********** PRE FLUSH ***********
********** ON FLUSH ***********
********** POST FLUSH ***********
i = 2
********** PRE FLUSH ***********
********** PRE FLUSH ***********
********** PRE FLUSH ***********
********** PRE FLUSH ***********
********** ON FLUSH ***********
********** POST FLUSH ***********
i = 3
********** PRE FLUSH ***********
********** PRE FLUSH ***********
********** PRE FLUSH ***********
********** PRE FLUSH ***********
********** PRE FLUSH ***********
********** ON FLUSH ***********
********** POST FLUSH ***********
i = 4
********** PRE FLUSH ***********
********** PRE FLUSH ***********
********** PRE FLUSH ***********
********** PRE FLUSH ***********
********** PRE FLUSH ***********
********** PRE FLUSH ***********
********** ON FLUSH ***********
********** POST FLUSH ***********
Таким образом, preFlush
вызывается один раз для каждого управляемого объекта (включая новый) + один раз, когда EntityManager
фактически сбрасывается.
По моему мнению, событие preFlush
должно вызываться один раз за операцию EntityManager#flush()
(как и другие события flush).
Я нашел код, вызывающий такое поведение: https://github.com/doctrine/doctrine2/blob/master/lib/Doctrine/ORM/UnitOfWork.php#L536
Вот мой вопрос: я ошибаюсь, Доктрина работает неправильно или мне чего-то не хватает?
2 answers
Я не могу сказать, было ли это намеренно или нет, но это кажется логичным. Количество вызовов PreFlush
соответствует количеству управляемых сущностей, но, вероятно, потому, что этот метод предназначен для обеспечения целостности сущности.
Обратите внимание, что количество вызовов PostFlush
не увеличивается. Если бы данные каждого объекта изменялись при сбросе, то PostFlush
вызывался бы снова для каждого из них.
В идеале $em->flush()
без аргументов следует вызывать только в конце выполнения сценарий (или, по крайней мере, очень мало раз). Чтобы гарантировать, что определенная сущность обрабатывается и сбрасывается при ее вызове, передайте сущность в качестве аргумента методу flush
.
preFlush
срабатывает при каждом вызове на $em->flush()
. postFlush
запускается только в том случае, если есть фактический набор изменений для фиксации. См. https://github.com/doctrine/doctrine2/pull/382 для обсуждения того, как изменить это postFlush
поведение.