При сохранении сущности Доктрина обновляется на другую Сущность, которую я не изменял

#symfony #doctrine

Вопрос:

У меня есть 2 сущности, User и Organization

 /**
 * @ORMEntity
 */
class User
{
    /**
     * @ORMId
     * @ORMGeneratedValue
     * @ORMColumn(type="integer")
     */
    private ?int $id;

    /**
     * @ORMColumn(type="string", length=180, unique=true)
     */
    private ?string $email;

    // ...

}

/**
 * @ORMEntity
 */
class Organization
{
    /**
     * @ORMId
     * @ORMGeneratedValue
     * @ORMColumn(type="integer")
     */
    private ?int $id;
    
    /**
     * @ORMColumn(type="integer")
     */
    private float $cron_payout_max_days_between;


    // ...
}
 

Случайным образом, когда я обновлял или создавал новую User строку БД, такую как эта:

 $user->setEmail('some@email.com');
$this->entityManager->persist($user);
$this->entityManager->flush();
 

Я заметил в профилировщике Symfony, что по какой-то причине между START TRANSACTION сущностью и COMMIT не связанными с User ней существами были запросы. В частности, такие запросы, как:

 UPDATE organization SET cron_payout_max_days_between = ? WHERE id = ?
 

Это сводило меня с ума, потому что казалось случайным. На некоторых страницах это происходило. На других-нет. Иногда для нескольких строк организации, иногда для всех, иногда для одной, а иногда ни для одной.

Я понял это после того, как провел 3 часа внутри отладчика, тысячу раз заходя в UnitOfWork. Я пишу этот пост, чтобы избавить от этого разочарования кого-то другого, кто может столкнуться с такой проблемой, потому что я ничего не нашел во время поиска ответа.

Ответ №1:

Эту проблему было легко не заметить.

 /**
 * @ORMColumn(type="integer")
 */
private float $cron_payout_max_days_between;
 

тип столбца был определен как целое число, но переменная PHP была с плавающей точкой. Это означало, что доктрина ВСЕГДА будет рассматривать ценность сущности как измененную, даже если я к ней не прикасался.

Почему это происходило случайным образом с одной, многими, всеми строками? Это зависит от того, какие строки загружаются в кэш другими частями кода. В любом случае, как только EntityManager::persist() функция была вызвана, каждый Organization объект, который был загружен в какой-то момент, уже был отмечен для обновления, потому что float 1.0 != int 1

Я надеюсь, что это сэкономит вам несколько часов вашего времени!

Просто для ясности, исправление было изменено на:

 /**
 * @ORMColumn(type="integer")
 */
private int $cron_payout_max_days_between;