如何从@Groups包含策略更新symfony2 / doctrine实体JMSSerializer反序列化实体

时间:2021-05-25 06:51:17

I'm trying to update symfony2/doctrine entities using JMSSerializer with an @ExclusionPolicy:None @Groups Inclusion Policy.

我正在尝试使用带有@ExclusionPolicy的JMSSerializer来更新symfony2 / doctrine实体:无@Groups包含策略。

 * @Serializer\ExclusionPolicy("none")
 */
 class Foo
 {
    /**
     * @Serializer\Groups({"flag","edit"})
     */
    protected $id;

    /**
     * @Serializer\Groups({"edit"})
     */
    protected $name;

    /**
     * @Serializer\Groups({"flag"})
     */
    protected $flag;

    /**
     * @Serializer\Exclude()
     */
    protected $createdBy;
 }

reference: http://jmsyst.com/libs/serializer/master/reference/annotations

参考:http://jmsyst.com/libs/serializer/master/reference/annotations

the result for the following record:

以下记录的结果:

Foo (id:1, name:'bar', flagged:false ,created_by:123)

is serialized using Group inclusion to avoid serializing information I don't need (associations, blobs, etc..) so when I want to update an entity I deserialize only the updated fields of the entity from the JSON.

使用Group包含序列化以避免序列化我不需要的信息(关联,blob等等)所以当我想要更新实体时,我只从JSON反序列化实体的更新字段。

$foo->setFlagged(true);
$data = $serializer->serialize($foo, 'json', SerializationContext::create()->setGroups(array("flag")));

result:
{id:1,flagged:true}

which when passed back to the application deserializes into the entity

传回应用程序时反序列化为实体

$foo = $serializer->deserialize($jsonFoo,'Foo','json');

result:
Foo (id:1, name:null, flagged:true, created_by:null)

The problem is when I try to merge the entity back into the doctrine entity manager:

问题是当我尝试将实体合并回到主题实体管理器时:

$foo = $em->merge($foo);
$em->persist($foo);
$em->flush();

The resulting foo is trying to update excluded properties (name,created_by) with null.

生成的foo尝试使用null更新排除的属性(name,created_by)。

How do I tell JMSSerializer or Doctrine Entity Managers merge that I don't want to overwrite existing properties with null?

如何告诉JMSSerializer或Doctrine Entity Manager合并我不想用null覆盖现有属性?

3 个解决方案

#1


17  

I found the answer.

我找到了答案。

$serializer is a service created by the symfony2 integration bundle JMSSerializerBundle.

$ serializer是由symfony2集成包JMSSerializerBundle创建的服务。

The default service is jms_serializer.serializer initializes the JMSSerializer with the default Object Constructor UnserializeObjectConstructor and for doctrine I needed to deserialize with the DoctrineObjectConstructor.

默认服务是jms_serializer.serializer使用默认的Object Constructor UnserializeObjectConstructor初始化JMSSerializer,对于我需要使用DoctrineObjectConstructor反序列化的doctrine。

because I only use JMSSerializer in the project for serialize/deserialize of doctrine entities, I overwrote JMSSerializerBundle's jms_serializer.object_constructor with the alias of the proper object constructor service.

因为我只在项目中使用JMSSerializer来序列化/反序列化doctrine实体,我用正确的对象构造函数服务的别名覆盖了JMSSerializerBundle的jms_serializer.object_constructor。

<service id="jms_serializer.object_constructor" alias="jms_serializer.doctrine_object_constructor" public="false"/>

Is there a better way to configure what object constructor the serializer uses?

有没有更好的方法来配置序列化程序使用的对象构造函数?

I also added the proper context to deserialize:

我还添加了反序列化的正确上下文:

$serializer->deserialize($jsonFoo,'Foo','json', DeserializationContext::create()->setGroups(array('flag')));

result:
Foo (id:1, name:'bar', flagged:true ,created_by:123)

Using the doctrine object constructor, it figures out that I want to find the object and only apply updates to fields provided in $jsonFoo (and the flag group). This totally eliminates the need for doctrines entity manager merge and I can just persist the object properly.

使用doctrine对象构造函数,它指出我想要找到对象并仅对$ jsonFoo(和标志组)中提供的字段应用更新。这完全消除了对doctrines实体管理器合并的需要,我可以正确地持久保存对象。

$em->persist($foo);
$em->flush();

#2


4  

in addition to @Heyflynn's answer (thanks!), I needed this to work with doctrine_mongodb, so I modified my services.yml as follows:

除了@Heyflynn的回答(谢谢!),我需要使用doctrine_mongodb,所以我修改了我的services.yml,如下所示:

services:
    jms_serializer.doctrine_object_constructor:
        class:        %jms_serializer.doctrine_object_constructor.class%
        public:       false
        arguments:    ["@doctrine_mongodb", "@jms_serializer.unserialize_object_constructor"]

    jms_serializer.object_constructor:
        alias: jms_serializer.doctrine_object_constructor

important fact is the @doctrine_mongodb as argument for jms_serializer.doctrine_object_constructor instead the original doctrine parameter in the bundle's services.xml:

重要的事实是@doctrine_mongodb作为jms_serializer.doctrine_object_constructor的参数,而不是bundle的services.xml中的原始doctrine参数:

    <service id="jms_serializer.doctrine_object_constructor" class="%jms_serializer.doctrine_object_constructor.class%" public="false">
        <argument type="service" id="doctrine"/>
        <argument type="service" id="jms_serializer.unserialize_object_constructor"/>
    </service>
    <service id="jms_serializer.unserialize_object_constructor" class="%jms_serializer.unserialize_object_constructor.class%" public="false" />
    <service id="jms_serializer.object_constructor" alias="jms_serializer.unserialize_object_constructor" public="false" />

#3


1  

To use JMS deserializer for MongoDB documents and ORM entities you can use

要为您可以使用的MongoDB文档和ORM实体使用JMS反序列化器

jms_serializer.doctrine_mongodb_object_constructor:
    class:        %jms_serializer.doctrine_object_constructor.class%
    public:       false
    arguments:    ["@doctrine_mongodb", "@jms_serializer.unserialize_object_constructor"]

jms_serializer.doctrine_object_constructor:
    class:        %jms_serializer.doctrine_object_constructor.class%
    public:       false
    arguments:    ["@doctrine", "@jms_serializer.doctrine_mongodb_object_constructor"]

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

As you see in jms_serializer.doctrine_object_constructor second argument (fallbackConstructor) is jms_serializer.doctrine_mongodb_object_constructor it means that if your object isn't entity then jms will try to use fallbackConstructor and if your deserialised object isn't Document either then will be used default unserialize_object_constructor

正如您在jms_serializer.doctrine_object_constructor中看到的那样,第二个参数(fallbackConstructor)是jms_serializer.doctrine_mongodb_object_constructor,这意味着如果您的对象不是实体,那么jms将尝试使用fallbackConstructor,如果您的反序列化对象不是Document,那么将使用默认的unserialize_object_constructor

if you deserialize entity

如果你反序列化实体

$em->persist($foo);
$em->flush();

if document

如果是文件

$dm->persist($foo);
$dm->flush();

#1


17  

I found the answer.

我找到了答案。

$serializer is a service created by the symfony2 integration bundle JMSSerializerBundle.

$ serializer是由symfony2集成包JMSSerializerBundle创建的服务。

The default service is jms_serializer.serializer initializes the JMSSerializer with the default Object Constructor UnserializeObjectConstructor and for doctrine I needed to deserialize with the DoctrineObjectConstructor.

默认服务是jms_serializer.serializer使用默认的Object Constructor UnserializeObjectConstructor初始化JMSSerializer,对于我需要使用DoctrineObjectConstructor反序列化的doctrine。

because I only use JMSSerializer in the project for serialize/deserialize of doctrine entities, I overwrote JMSSerializerBundle's jms_serializer.object_constructor with the alias of the proper object constructor service.

因为我只在项目中使用JMSSerializer来序列化/反序列化doctrine实体,我用正确的对象构造函数服务的别名覆盖了JMSSerializerBundle的jms_serializer.object_constructor。

<service id="jms_serializer.object_constructor" alias="jms_serializer.doctrine_object_constructor" public="false"/>

Is there a better way to configure what object constructor the serializer uses?

有没有更好的方法来配置序列化程序使用的对象构造函数?

I also added the proper context to deserialize:

我还添加了反序列化的正确上下文:

$serializer->deserialize($jsonFoo,'Foo','json', DeserializationContext::create()->setGroups(array('flag')));

result:
Foo (id:1, name:'bar', flagged:true ,created_by:123)

Using the doctrine object constructor, it figures out that I want to find the object and only apply updates to fields provided in $jsonFoo (and the flag group). This totally eliminates the need for doctrines entity manager merge and I can just persist the object properly.

使用doctrine对象构造函数,它指出我想要找到对象并仅对$ jsonFoo(和标志组)中提供的字段应用更新。这完全消除了对doctrines实体管理器合并的需要,我可以正确地持久保存对象。

$em->persist($foo);
$em->flush();

#2


4  

in addition to @Heyflynn's answer (thanks!), I needed this to work with doctrine_mongodb, so I modified my services.yml as follows:

除了@Heyflynn的回答(谢谢!),我需要使用doctrine_mongodb,所以我修改了我的services.yml,如下所示:

services:
    jms_serializer.doctrine_object_constructor:
        class:        %jms_serializer.doctrine_object_constructor.class%
        public:       false
        arguments:    ["@doctrine_mongodb", "@jms_serializer.unserialize_object_constructor"]

    jms_serializer.object_constructor:
        alias: jms_serializer.doctrine_object_constructor

important fact is the @doctrine_mongodb as argument for jms_serializer.doctrine_object_constructor instead the original doctrine parameter in the bundle's services.xml:

重要的事实是@doctrine_mongodb作为jms_serializer.doctrine_object_constructor的参数,而不是bundle的services.xml中的原始doctrine参数:

    <service id="jms_serializer.doctrine_object_constructor" class="%jms_serializer.doctrine_object_constructor.class%" public="false">
        <argument type="service" id="doctrine"/>
        <argument type="service" id="jms_serializer.unserialize_object_constructor"/>
    </service>
    <service id="jms_serializer.unserialize_object_constructor" class="%jms_serializer.unserialize_object_constructor.class%" public="false" />
    <service id="jms_serializer.object_constructor" alias="jms_serializer.unserialize_object_constructor" public="false" />

#3


1  

To use JMS deserializer for MongoDB documents and ORM entities you can use

要为您可以使用的MongoDB文档和ORM实体使用JMS反序列化器

jms_serializer.doctrine_mongodb_object_constructor:
    class:        %jms_serializer.doctrine_object_constructor.class%
    public:       false
    arguments:    ["@doctrine_mongodb", "@jms_serializer.unserialize_object_constructor"]

jms_serializer.doctrine_object_constructor:
    class:        %jms_serializer.doctrine_object_constructor.class%
    public:       false
    arguments:    ["@doctrine", "@jms_serializer.doctrine_mongodb_object_constructor"]

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

As you see in jms_serializer.doctrine_object_constructor second argument (fallbackConstructor) is jms_serializer.doctrine_mongodb_object_constructor it means that if your object isn't entity then jms will try to use fallbackConstructor and if your deserialised object isn't Document either then will be used default unserialize_object_constructor

正如您在jms_serializer.doctrine_object_constructor中看到的那样,第二个参数(fallbackConstructor)是jms_serializer.doctrine_mongodb_object_constructor,这意味着如果您的对象不是实体,那么jms将尝试使用fallbackConstructor,如果您的反序列化对象不是Document,那么将使用默认的unserialize_object_constructor

if you deserialize entity

如果你反序列化实体

$em->persist($foo);
$em->flush();

if document

如果是文件

$dm->persist($foo);
$dm->flush();