@Emprove

Почему при создании записи обновляются все связанные сущности?

"laravel-doctrine/extensions": "1.4.0",
"laravel-doctrine/orm": "1.7.13",
"laravel/lumen-framework": "v8.3.4",

DOCTRINE_PROXY_AUTOGENERATE=true
DOCTRINE_CACHE=array
DOCTRINE_METADATA_CACHE=array
DOCTRINE_QUERY_CACHE=array
DOCTRINE_RESULT_CACHE=array

Включил логгинг запросов в postgres 12 и увидел, что доктрина обновляет кучу сущностей, которые я в коде не обновляю. К примеру, при добавлении комментария к заказу, обновляются и все связи самого заказа. Как я понимаю, unit of work некорректно отрабатывает. Вот даже последней строкой обновляется user, хотя у меня нигде юзер из кода не обновляется. Аннотации cascade не стоят нигде. Использую flush(). Если сделать flush($entity) то все корректно работает, конечно. Но это скорее костыль, чем решение. clear() не использую нигде.

2022-01-29 15:29:31.141 UTC [674] LOG:  execute <unnamed>: INSERT INTO order_comments (id, created_at, updated_at, order_id, text, created_by) VALUES ($1, $2, $3, $4, $5, $6)
2022-01-29 15:29:31.141 UTC [674] DETAIL:  parameters: $1 = '28', $2 = '2022-01-29 18:29:31', $3 = '2022-01-29 18:29:31', $4 = '55', $5 = 'test', $6 = '1'
2022-01-29 15:29:31.142 UTC [674] LOG:  execute <unnamed>: UPDATE order_statuses SET id = $1, updated_at = $2 WHERE id = $3
2022-01-29 15:29:31.142 UTC [674] DETAIL:  parameters: $1 = '2', $2 = '2022-01-29 18:29:31', $3 = '2'
2022-01-29 15:29:31.142 UTC [674] LOG:  execute <unnamed>: UPDATE shipments SET id = $1, updated_at = $2 WHERE id = $3
2022-01-29 15:29:31.142 UTC [674] DETAIL:  parameters: $1 = '1', $2 = '2022-01-29 18:29:31', $3 = '1'
2022-01-29 15:29:31.143 UTC [674] LOG:  execute <unnamed>: UPDATE orders SET id = $1, shipment_id = $2, order_status_id = $3, cost = $4, updated_at = $5 WHERE id = $6
2022-01-29 15:29:31.143 UTC [674] DETAIL:  parameters: $1 = '55', $2 = '1', $3 = '2', $4 = '3343', $5 = '2022-01-29 18:29:31', $6 = '55'
2022-01-29 15:29:31.143 UTC [674] LOG:  execute <unnamed>: UPDATE order_has_products SET id = $1, price = $2 WHERE id = $3
2022-01-29 15:29:31.143 UTC [674] DETAIL:  parameters: $1 = '69', $2 = '3000', $3 = '69'
2022-01-29 15:29:31.144 UTC [674] LOG:  execute <unnamed>: UPDATE order_has_products SET id = $1, price = $2 WHERE id = $3
2022-01-29 15:29:31.144 UTC [674] DETAIL:  parameters: $1 = '70', $2 = '145', $3 = '70'
2022-01-29 15:29:31.144 UTC [674] LOG:  execute <unnamed>: UPDATE users SET id = $1, updated_at = $2 WHERE id = $3


UPD: вывел changesets и заметил, что даты обновляются всегда. У меня во всех сущностях стоит private ?\DateTime $created_at ну и так далее. И changeset получается всегда не пустой, даже если ничего не менять по факту. Как я понял, надо копать сюда: https://github.com/doctrine/orm/issues/7583
  • Вопрос задан
  • 134 просмотра
Решения вопроса 1
@tukreb
Доктрина обновляет всегда сущность если фиксирует любое её изменение.
Самый простой пример, например в БД дата записана в одном тип дате, а при доставание вы её конвертируете в самом объекте в другой тип даты.
Другой пример, в базе данных у вас данные в BIGINT, а доктрина при доставание конвертирует их в строку.
Чтобы избежать этого, вам нужно сделать так, чтобы в сущность попадали уже готовый формат данных полностью идентичный сохранённым в БД.
Возможно вам нужно написать свой тип данных.
https://www.doctrine-project.org/projects/doctrine...

Пример фикса для bigint
class BigIntType extends Type
{
    public function convertToPHPValue($value, AbstractPlatform $platform): ?int
    {
        return $value === null ? null : (int) $value; //до того как данные попали в сущность, мы насильно конвертируем в int (иначе будет строка)
    }

    public function getSQLDeclaration(array $column, AbstractPlatform $platform): string
    {
        return $platform->getBigIntTypeDeclarationSQL($column);
    }

    public function getName(): string
    {
        return Types::BIGINT;
    }
}
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы