反序列化并保持与JMS Serializer

时间:2017-04-03 15:13:36

标签: symfony doctrine-orm jmsserializerbundle

我试图让以下工作:

我有一个像以下的实体:

<?php

namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use JMS\Serializer\Annotation as JMS;

/**
 * Contact
 *
 * @ORM\Table()
 * @ORM\Entity()
 */

class Contact
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=255)
     */
    private $name;


    /**
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\ServiceClient", inversedBy="contacts")
     * @ORM\JoinColumn(name="service_client", referencedColumnName="service_client")
     *
     * @JMS\Type("AppBundle\Entity\ServiceClient")
     * @JMS\SerializedName("serviceClient")
     */
    private $serviceClient;

}

我通过HTTP请求发送以下JSON(帖子,它是新的联系人,没有ID):

{
 "name": "Lorem Ipsum",
 "serviceClient": {"service_client": "ipsum"}
}

我期望JMS Serializer能够解析这种关系,并让我像这样坚持Contact对象:

<?php
$contact = $this->get('serializer')->deserialize(
    $request->getContent(),
    Contact::class, 'json'
);
$this->em->persist($contact);
$this->em->flush();

事实上我已经开始工作了(我发誓它正在运作)但是现在它给了我以下错误:

  

通过这种关系找到了一个新的实体   &#39;的appbundle \实体\联系#serviceClient&#39;没有配置   实体的级联持久化操作:   的appbundle \实体\ ServiceClient @ 000000006fafb93e00007f122bd10320。至   解决此问题:显式调用EntityManager#persist()on   这个未知的实体或配置级联持久存在此关联   映射例如@ManyToOne(..,cascade = {\&#34; persist \&#34;})。如果你   无法找出导致问题实施的实体   &#39;的appbundle \实体\ ServiceClient #__的toString()&#39;得到一个线索。&#34;

所以它试图坚持实体...我不想要的东西,因为实体已经存在。我只想要Doctrine来放置引用,即外键。

编辑:它似乎是构造函数,如果我将其设置为doctrine_object_constructor它就像魔法一样,我不理解的是它为什么停止工作第一名。

任何人都可以分享任何想法或更清洁的方式来做我做的事情吗?

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

2 个答案:

答案 0 :(得分:0)

Doctrine 无法将您的关系映射到数据库中的现有记录时会发生此问题,因此它将尝试使用JSON对象中的数据创建一个新记录。

在您的情况下,JSON对象: {“service_client”:“ipsum”} 无法映射到现有的 ServiceClient 实例。

这是因为默认的JMS对象构造函数调用 unserialize 函数(如果你定义了这个方法,将是你的Entity中的那个)来构造对象,这意味着这个对象将始终被 Doctrine 视为新对象(从未被持久化)。

通过 doctrine_object_constructor JMS 将从 Doctrine 获取对象。该对象来自 Doctrine ,不仅具有您在实体中定义的属性和方法,还有关于它是否是现有属性的元数据,它是数据库中的相应行(所以 Doctrine < / strong>可以检测稍后对记录进行的更新并处理它,因此 Doctrine 可以避免不正确的持久性。

答案 1 :(得分:-1)

Doctrine将尝试使用反序列化中给出的ServiceClient实体的引用来保持Contact。在manyToOne定义级别的实体定义中,您需要添加:

@ORM \ ManyToOne(targetEntity =&#34; AppBundle \ Entity \ ServiceClient&#34;,inversedBy =&#34; contacts&#34;,cascade = {&#34; persist&#34;})