Доктрина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

Вот мой вопрос: я ошибаюсь, Доктрина работает неправильно или мне чего-то не хватает?

Author: wachme, 2013-11-11

2 answers

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

Обратите внимание, что количество вызовов PostFlush не увеличивается. Если бы данные каждого объекта изменялись при сбросе, то PostFlush вызывался бы снова для каждого из них.

В идеале $em->flush() без аргументов следует вызывать только в конце выполнения сценарий (или, по крайней мере, очень мало раз). Чтобы гарантировать, что определенная сущность обрабатывается и сбрасывается при ее вызове, передайте сущность в качестве аргумента методу flush.

 1
Author: Flosculus, 2013-11-12 21:02:50

preFlush срабатывает при каждом вызове на $em->flush(). postFlush запускается только в том случае, если есть фактический набор изменений для фиксации. См. https://github.com/doctrine/doctrine2/pull/382 для обсуждения того, как изменить это postFlush поведение.

 1
Author: andig, 2014-05-09 05:36:32