Отношение десериализации ко многим JMS не удаляется с помощью orphanremoval

У меня есть сборка Symfony rest api с fos restbundle, и я десериализую запрос JSON PUT, чтобы обновить объект доктрины с отношением ко многим. Однако дочерние объекты для многих, настроенные с помощью orphanremoval=true, не удаляются из базы данных, если они не присутствуют в данных json.

Полезные данные запроса PUT:

{
    "id": 1,
    "name":"Some name",
    "export_destinations": [
        {
            "id": 1,
            "type": "USER_STORAGE",
            "user": {"id": 5}
        }
        {
            "id": 2,
            "type": "SYSTEM_STORAGE"
        }
    ]
}

Действие контроллера:

 /**
  * @Rest\Put("{id}")
  * @ParamConverter(
  *     "exportJob",
  *     converter = "fos_rest.request_body",
  *     options = {"deserializationContext" = {"groups" = {"put"}}}
  * )
  * @Rest\View(serializerGroups = {"details"})
  * @param ExportJob $exportJob
  * @return ExportJob
  */
public function putAction(ExportJob $exportJob)
{
    $this->getManager()->persist($exportJob);
    $this->getManager()->flush();

    return $exportJob;
}

Сущность ExportJob

/**
 * @ORM\Entity()
 */
class ExportJob
{
    /**
     * @var ArrayCollection|ExportDestination[]
     *
     * @ORM\OneToMany(targetEntity = "ExportDestination", mappedBy = "exportJob", cascade = {"persist", "remove", "merge"}, orphanRemoval=true)
     */
    protected $exportDestinations;

    /**
     * @param ExportDestination $exportDestination
     * @return $this
     */
    public function addExportDestination(ExportDestination $exportDestination)
    {
        $exportDestination->setExportJob($this);
        $this->exportDestinations->add($exportDestination);

        return $this;
    }

    /**
     * @param ExportDestination $exportDestination
     * @return $this
     */
    public function removeExportDestination(ExportDestination $exportDestination)
    {
        $this->exportDestinations->removeElement($exportDestination);
        $exportDestination->setExportJob(null);

        return $this;
    }
}

Метаданные JMS

MyProject\ExportBundle\Entity\ExportJob:
    exclusion_policy: ALL
    properties:
        id:
            groups: ['list', 'details', 'put']
            expose: true
        name:
            groups: ['list', 'details', 'put', 'patch', 'post']
            expose: true
        exportDestinations:
            groups: ['details', 'put', 'patch', 'post']
            expose: true
            type: 'ArrayCollection<MyProject\ExportBundle\Entity\ExportDestination>'

Я использую DoctrineObjectConstructor

    jms_serializer.object_constructor:
        alias: jms_serializer.doctrine_object_constructor
        public: false

Теперь, когда я оставляю второй объект из массива export_destinations в полезной нагрузке json, мой exportJob в действии контроллера имеет только один объект exportDestination в коллекции массивов после десериализации. Но когда я упорствую, я ожидаю, что доктрина удалит exportDestination из базы данных, поскольку у меня есть orphanremoval=true.

Я думаю, проблема в том, что метод removeExportDestination() никогда не вызывается во время десериализации, что должно установить отношение к нулю на обратной стороне. Если этого не произойдет, он не удалит объект, поскольку он еще не стал сиротой.

Есть ли способ, которым JMS будет использовать методы добавления / удаления для ArrayCollections во время десериализации?

Я также пробовал использовать merge() вместо persist(), но без разницы

Можете ли вы добавить код объекта ExportDestination и его метаданные jms?

Jannes Botis 12.04.2018 10:25
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
6
1
277
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы правы в том, что «метод removeExportDestination () никогда не вызывается во время десериализации».

Вы можете определить свойство аксессуар, чтобы делать то, что вы хотите:

exportDestinations:
        groups: ['details', 'put', 'patch', 'post']
        expose: true
        type: 'ArrayCollection<AppBundle\Entity\ExportDestination>'
        accessor:
            getter: "getExportDestinations"
            setter: "setExportDestinations"

и в сущности ExportJob:

public function getExportDestinations()
{
    return $this->exportDestinations;
}

public function setExportDestinations($exportDestinations)
{
    // first detach existing related entities.
    foreach ($this->exportDestinations as $exportDestination) {
        $exportDestination->setExportJob(null);
    }
    $this->exportDestinations = $exportDestinations;
    foreach ($exportDestinations as $exportDestination) {
        $exportDestination->setExportJob($this);
    }
}

так что во время десериализации вызывается "setExportDestinations", который заботится об удалении связи.

Сказав это, я не уверен, следует ли вам использовать orphanremoval=true в отношении, поскольку

orphanRemoval=true, even if you will remove given ExportDestination from one ExportJob, and then attach to another ExportJob, this ExportDestination will be deleted during persist, because the reference has been deleted.

Я бы посоветовал удалить его и найти другой способ удаления "сиротских" сущностей ExportDestination.

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