Flush when you are done

02. August 2020 Doctrine, Symfony 0

Timing. It’s all about timing.

Using Doctrine as your ORM for example, starting a transaction and committing it to the database, the flush sequence, is one of the most costly operations in your application. Sadly, as a developer I know this trap all to well.

Imagine writing some functionality where you have to modify some complex entities in your application. As a well instructed developer you let your controller or console command delegate operations to other classes. These classes would probably have a dependency of an entity manager residing within to fetch from the database and persist into the entity manager. This much is nothing new to most developers.

Let’s look at an example:

<?php

...

class SomeAction {

    private $entityManager;

    public function __construct (EntityManagerInterface $entityManager) 
    {
        $this->entityManager = $entityManager;
    }

    public function execute(int $id, array $data)
    {
        $entity = $this->entityManager->getRepository(SomeEntity::class)->find($id);
        // Perform some actions with $data
        $this->entityManager->flush();
    }
}

This shows a simple execution of fetching, modifying and storing the entity. Now, this class ‘SomeAction’ could be called once in your controller and that would be it in that lifecycle of request / response.

But what if this action would be re-used in other classes. What if you made a series of classes performing there own logic and then flushing the result to the database. Nesting these classes would then result in unexpected and maybe even undesirable behavior. Not to mention a costly one.

There is no simple solution to this other than be mindful of the situation. Program your application in manner so you can be sure of the fact there is only one flush. I do however have a few thoughts on how to cope with it.

  • Let your classes operate on the task they should be doing. The controller performs the flush.
  • Use a true / false switch to control the flushing. Useful when re-using a block of code and only flushing on the last operation.

Some rules are made to be broken though. An example of such is processing large amounts of data. In this scenario you’ll be likely to flush a few times, depending on the size of your UnitOfWork. If your application starts running slow due to processing bulks of data at a time, chances are your UnitOfWork is consuming a lot of memory. This is when you perform a flush operation, clear your entity manager and resume operation.


Leave a Reply

Your email address will not be published. Required fields are marked *