Как заменить EntityManager :: merge в Doctrine 3?

Я работаю над проектом веб-приложения на основе Symfony 2.8, которое в настоящее время использует Doctrine 2. Проект представляет собой простое приложение со списком дел, которое можно синхронизировать с мобильным приложением (iOS / Android).

Читая примечания к обновлению Doctrine 3, я обнаружил, что EntityManager::mergeбольше не будет поддерживаться.

An alternative to EntityManager#merge() is not provided by ORM 3.0, since the merging semantics should be part of the business domain rather than the persistence domain of an application. If your application relies heavily on CRUD-alike interactions and/or PATCH restful operations, you should look at alternatives such as JMSSerializer.

Я не уверен, как лучше / правильно заменить EntityManager::merge?

Где использовать слияние:

Во время синхронизации мобильных приложений с веб-приложением данные передаются как сериализованный JSON, который затем десериализуется JMSSerializer в объект сущности. Когда веб-приложение получает объект ToDoEntry таким образом, это может быть новая запись ToDo-Entry (еще не известная в веб-приложении) или обновленная существующая запись. В любом случае полученный объект не управляется EntityManager. Таким образом, $em->persist($receivedObject) всегда будет пытаться вставить новый объект. Это не удастся (из-за уникального ограничения идентификатора), если ToDo-Entry уже существует в веб-приложении и нуждается в обновлении.

Вместо этого используется $em->merge($receivedObject), который автоматически проверяет, требуется ли вставка или обновление.

Как решить эту проблему?

Конечно, я мог бы проверить все полученные объекты, существует ли уже сущность с таким же идентификатором. В этом случае можно загрузить существующий объект и обновить его свойства вручную. Однако это было бы очень обременительно. В реальном проекте, конечно, используется много разных сущностей, и для каждого типа / класса сущности потребуется собственная обработка, чтобы проверить, какие свойства необходимо обновить. Нет лучшего решения?

Проверять, существует ли объект или нет, и делать что-либо соответственно, на мой взгляд, не является обременительным и действительно должно выполняться вами в вашей бизнес-логике. Ничего необычного.

Jim Panse 06.07.2018 12:58

Проблема не в самой проверке, а в обновлении существующих сущностей. Каждому типу сущности потребуется свой собственный метод для сравнения / переопределения существующих свойств с одним из полученных объектов. Каждый раз, когда свойство добавляется к сущности, также необходимо обновить код синхронизации / обновления. Никакого волшебства, конечно, но гораздо больше работы, чем простой вызов $em->merge(...). Это действительно правильный путь?

Andrei Herford 06.07.2018 13:25

На мой взгляд, вам не нужно менять свой метод каждый раз, когда свойство удаляется или добавляется ... просто напишите гибкий метод слияния, который будет перебирать ваши свойства и делать все, что вы хотите, с новыми / старыми значениями. Они удалили эту функцию, потому что никто не знает ваших требований и того, как должна вести себя функция слияния. Что, если оба объекта (новый и старый) заполнены? Кто победит? Это то, что вы должны решить с учетом ваших требований, и это часть бизнес-логики, а не ответственность базы данных.

Jim Panse 06.07.2018 13:43

Предположим, что объект ToDoEntry получает новое свойство person с setPerson(...) и getPerson(). Как может существующий метод merge обрабатывать это свойство, не зная, что оно существует? Придется добавить что-то вроде $existingEntity->setPerson($receivedEntity->getPerson()), или я чего-то упускаю?

Andrei Herford 06.07.2018 13:52

Для этого вы можете использовать отражение. php.net/manual/en/reflectionclass.getproperties.php ...

Jim Panse 06.07.2018 14:18

Если вам нравится поведение $ em-> merge, просто скопируйте и вставьте функцию в свою кодовую базу.

marcodl 13.12.2020 11:11
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Symfony Station Communiqué - 17 февраля 2023 г
Symfony Station Communiqué - 17 февраля 2023 г
Это коммюнике первоначально появилось на Symfony Station , вашем источнике передовых новостей Symfony, PHP и кибербезопасности.
Управление ответами api для исключений на Symfony с помощью KernelEvents
Управление ответами api для исключений на Symfony с помощью KernelEvents
Много раз при создании api нам нужно возвращать клиентам разные ответы в зависимости от возникшего исключения.
14
6
2 982
2

Ответы 2

Вы можете попробовать использовать метод registerManaged () в Doctrine \ ORM \ UnitOfWork.

// $this->em <--- Doctrine Entity Manager
// $entity <--- detached Entity (and we know that this entity already exists in DB for example)

$id = [$entity->getId()]; //array
$data = $entity->toArray(); //array

$this->em->getUnitOfWork()->registerManaged($entity, $id, $data);

Конечно, вы можете проверить состояние своей сущности с помощью getEntityState () из Doctrine \ ORM \ UnitOfWork до / после выполнения необходимых действий.

$this->eM->getUnitOfWork()->getEntityState($entity, $assert = 3)

$assert <-- This parameter can be set to improve performance of entity state detection by potentially avoiding a database lookup if the distinction between NEW and DETACHED is either known or does not matter for the caller of the method.

функция registerManaged помечена как @internal и не должна использоваться, другого пути нет?

patryno 18.02.2021 10:08

На самом деле код для обработки этого может состоять всего из нескольких строк. В фоновом режиме Doctrine выдаст запрос для поиска вашей сущности, если она еще не находится в памяти, поэтому вы можете сделать то же самое, выполнив запрос самостоятельно с включенным кешем результатов, а затем просто используя PropertyAccessor для сопоставления данных.

https://symfony.com/doc/current/components/property_access.html

См. Эту суть для POC https://gist.github.com/stevro/99060106bbe54d64d3fbcf9a61e6a273

Другие вопросы по теме