JMS 反序列化对多关系不会用 orphanremoval 删除

JMS unserialize to-many relation does not remove with orphanremoval

我有一个使用 fos restbundle 构建的 Symfony rest api,我正在反序列化一个 json PUT 请求,以便更新具有一对多关系的学说实体。 但是,当 json 数据中不存在时,配置为 orphanremoval=true 的多对多子对象不会从数据库中删除。

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

现在,当我在 json 负载中遗漏 export_destinations 数组中的第二个对象时,控制器操作中的 exportJob 在反序列化后的数组集合中只有一个 exportDestination 对象。 但是当我坚持时,我希望学说从数据库中删除 exportDestination,因为我有 orphanremoval=true.

我认为问题在于,removeExportDestination() 方法在反序列化过程中从未被调用,应该在反面将关系设置为 null。如果那没有发生,它不会删除该实体,因为它还没有成为孤儿。

有没有办法让 JMS 在反序列化期间对 ArrayCollections 使用 add/remove 方法?

我也尝试过使用 merge() 而不是 persist() 但没有任何区别

你说得对 "the removeExportDestination() method never gets called during deserialization"。

您可以定义 accessor 属性 来执行您想要的操作:

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.

我建议删除它并找到另一种方法来删除 "orphan" ExportDestination 实体。