在symfony2中使用jmsSerializerBundle进行序列化然后反序列化子实体会在保存父实体时抛出异常

时间:2014-10-24 00:39:23

标签: symfony doctrine-orm jmsserializerbundle

我的应用程序有一个名为“client”的实体,它被注入每个请求对象。

为了提高性能,我设置了一个自定义缓存,并使用JMSSerializer来序列化和缓存客户端对象。当请求进入时,缓存返回序列化的Client对象,JMS对其进行反序列化。

我的应用程序创建其他实体,称之为ChildEntities,并通过ChildEntity上的ManyToOne关系将它们与Client对象关联。

这很好用,直到我开始通过反序列化缓存数据来加载这些对象,而不是使用Doctrine从MySQL数据库加载它们。 Doctrine现在抛出了这个错误:

通过“\ acme \ bundle \ Entity \ ChildEntity#client”关系找到了一个新实体,该关系未配置为对实体进行级联持久操作:ClientName。要解决此问题:在此未知实体上显式调用EntityManager#persist()或在映射中配置级联持久保存此关联,例如@ManyToOne(..,cascade = {“persist”})

所以,如果我正确地理解了这个错误,似乎Doctrine认为我的Client对象是由ChildEntity对象上的ManyToOne关系引用的,是 new 对象(即使我是用它需要保存的ID来反序列化它,但不会因为没有设置级联而停止。

我反对反序列化对象的策略是错误的吗?有没有办法将它们反序列化为代理对象,或者解决此问题的其他方法?我更喜欢将自定义缓存用于教义缓存。

2 个答案:

答案 0 :(得分:3)

当我最终找到合适的搜索短语时想出这个。

我使用的是默认对象构造函数,我需要使用Doctrine对象构造函数。

为此,我将此添加到我的services.yml:

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

答案 1 :(得分:1)

我也使用这个模块,并以json格式保存序列化的教义实体。

所以,我发现我必须配置Spea / JMSSerializerModule来使用DoctrineObjectConstructor而不是UnserializeObjectConstructor。

但是,与UnserializeObjectConstructor相反,DoctrineObjectConstructor不是一个简单的可调用类。构造函数需要两个对象:

  • interface Doctrine \ Common \ Persistence \ ManagerRegistry $ managerRegistry
  • interface JMS \ Serializer \ Construction \ ObjectConstructorInterface $ fallbackConstructor

问题在于没有接口ManagerRegistry的实现,显然,它没有工厂。

我通过在composer.json中添加此依赖项https://github.com/eddiejaoude/zf2-doctrine2-manager-registry-service来解决此问题。此模块通过服务管理器条目 Doctrine \ ManagerRegistry 提供接口ManagerRegistry的实现。

安装完成后,我为DoctrineObjectConstructor创建了一个工厂:

<?php
namespace Example\Service;

use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use JMS\Serializer\Construction\DoctrineObjectConstructor;

class DoctrineObjectConstructorFactory implements FactoryInterface
{
    /* (non-PHPdoc)
     * @see \Zend\ServiceManager\FactoryInterface::createService()
     */
    public function createService(ServiceLocatorInterface $serviceLocator)
    {
        $serv1 = $serviceLocator->get('Doctrine\ManagerRegistry');
        $serv2 = $serviceLocator->get('jms_serializer.unserialize_object_constructor');
        $service = new DoctrineObjectConstructor($serv1, $serv2);
        return $service;
    }

}

并在我的module.config.php中添加了这些条目:

'service_manager' => array(
    'factories' => array(
        'jms_serializer.doctrine_object_constructor' => 'Example\Service\DoctrineObjectConstructorFactory'
    ),
    'aliases' => array(
        'jms_serializer.object_constructor' => 'jms_serializer.doctrine_object_constructor'
    ),
),

就是这样。现在,它有效。

我在这里写了一个问题:https://github.com/Spea/JMSSerializerModule/issues/12因为我认为我们不应该添加外部模块来执行此操作。