Я работаю над проектом веб-приложения на основе 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), который автоматически проверяет, требуется ли вставка или обновление.
Как решить эту проблему?
Конечно, я мог бы проверить все полученные объекты, существует ли уже сущность с таким же идентификатором. В этом случае можно загрузить существующий объект и обновить его свойства вручную. Однако это было бы очень обременительно. В реальном проекте, конечно, используется много разных сущностей, и для каждого типа / класса сущности потребуется собственная обработка, чтобы проверить, какие свойства необходимо обновить. Нет лучшего решения?
Проблема не в самой проверке, а в обновлении существующих сущностей. Каждому типу сущности потребуется свой собственный метод для сравнения / переопределения существующих свойств с одним из полученных объектов. Каждый раз, когда свойство добавляется к сущности, также необходимо обновить код синхронизации / обновления. Никакого волшебства, конечно, но гораздо больше работы, чем простой вызов $em->merge(...). Это действительно правильный путь?
На мой взгляд, вам не нужно менять свой метод каждый раз, когда свойство удаляется или добавляется ... просто напишите гибкий метод слияния, который будет перебирать ваши свойства и делать все, что вы хотите, с новыми / старыми значениями. Они удалили эту функцию, потому что никто не знает ваших требований и того, как должна вести себя функция слияния. Что, если оба объекта (новый и старый) заполнены? Кто победит? Это то, что вы должны решить с учетом ваших требований, и это часть бизнес-логики, а не ответственность базы данных.
Предположим, что объект ToDoEntry получает новое свойство person с setPerson(...) и getPerson(). Как может существующий метод merge обрабатывать это свойство, не зная, что оно существует? Придется добавить что-то вроде $existingEntity->setPerson($receivedEntity->getPerson()), или я чего-то упускаю?
Для этого вы можете использовать отражение. php.net/manual/en/reflectionclass.getproperties.php ...
Если вам нравится поведение $ em-> merge, просто скопируйте и вставьте функцию в свою кодовую базу.




Вы можете попробовать использовать метод 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 и не должна использоваться, другого пути нет?
На самом деле код для обработки этого может состоять всего из нескольких строк. В фоновом режиме Doctrine выдаст запрос для поиска вашей сущности, если она еще не находится в памяти, поэтому вы можете сделать то же самое, выполнив запрос самостоятельно с включенным кешем результатов, а затем просто используя PropertyAccessor для сопоставления данных.
https://symfony.com/doc/current/components/property_access.html
См. Эту суть для POC https://gist.github.com/stevro/99060106bbe54d64d3fbcf9a61e6a273
Проверять, существует ли объект или нет, и делать что-либо соответственно, на мой взгляд, не является обременительным и действительно должно выполняться вами в вашей бизнес-логике. Ничего необычного.