【问题标题】:How to handle recursive objects with JMS Serializer如何使用 JMS 序列化器处理递归对象
【发布时间】:2016-04-15 07:21:48
【问题描述】:

我正在尝试序列化和反序列化 Doctrine 对象图。

结构相当复杂,但这个例子总结了我的问题:

有一个 Company 实体与 Employee 具有 OneToMany 关系。
Employee 实体与 Company 具有多对一关系。

这个序列化如下:

{
    "company": {
        "name": "MegaCorp",
        "employees": [{
            "name": "John Doe",
            "company": null
        }]
    }
}

所以nulls 引用了Employee 的父Company。对于序列化,这是可以的。 但是现在当我反序列化这个 json 时,我在 Employee 对象中得到了一个 null Company。我想要(并期望)得到对父 Company 的正确引用。

这是否可以使用 JMS 序列化程序实现,如果可以,如何实现?
如果不可能,有什么好的解决方法?记住这是一个很大的图,我不想手动做。

【问题讨论】:

  • 不要使引用为空,而是使用它的 ID。基本上,您需要一个代理而不是真实对象。我不知道 JMS 是否支持这个开箱即用。
  • 这将是一个可能的解决方案,但实际上问题是:JMS 是否支持类似的东西?
  • 我知道它有 @preSerialize@postSerialize 钩子。所以这是可行的。
  • 是的,我现在正在研究这个,但我觉得这不是一个不常见的用例,因此希望 JMS 默认支持它。
  • 你试过MaxDepth()吗?

标签: php jmsserializerbundle jms-serializer


【解决方案1】:

不幸的是,在反序列化时,序列化程序无法知道对象是否相同或实际上是相同的对象。即使您可以递归地嵌套它们。

但是,将@Accessor注解与一些业务逻辑结合起来,你可以得到想要的结果。所以离开你的例子:

class Company {
    /**
     * @Accessor(setter="addEmployees")
     */
    private $employees;

    public function addEmployee(Employee $employee)
    {
        if (!$this->employees->contains($employee)) {
            $this->employees[] = $employee;
            $employee->setCompany($this);
        }
    }

    public function addEmployees($employees)
    {
        foreach ($employees as $employee) {
            $this->addEmployee($employee);
        }
    }
}

class Employee {
    /**
     * @Accessor(setter="setCompany")
     */
    private $company;

    public setCompany(Company $company = null)
    {
        $this->company = $company;

        if ($company) {
            $company->addEmployee($this);
        }
    }
}

我认为这是一种比使用@PostDeserialize 更自然的方法,因为您的代码中可能已经包含其中一些方法。此外,它确保了双方的合同,所以如果你从Employee开始,你会得到相同的结果。

【讨论】:

  • 这实际上比我目前在 Company 上使用 PostDeserialize 挂钩的解决方案稍微好一点。基本思想是一样的。
  • 是的。恐怕没有办法解决这个问题......正如我所说,除了由 json 结构对其自身强制执行的关系之外,序列化程序无法获取任何关系。
  • 我认为你是对的。我现在使用@Accessor 方法实现了它,就像一个魅力。谢谢!
【解决方案2】:

当您反序列化对象后,如何手动设置引用?像这样的:

class Company { 

    ....

    @PostDeserialize
    public function setReferences()
    {
        foreach( $this->employees as $employee ){
            $employee->setCompany( $this );
        }
    }
}

【讨论】:

    【解决方案3】:

    让您的 JSON 实体尽可能简单是一个好习惯!如果您必须处理此类问题,那么是时候重新考虑您的数据模型了!

    另外,你有没有想过使用 HATEOAS(Hypermedia as the Engine of Application State)是一个原则,即应该使用超文本链接来创建更好的 API 导航。看起来像这样:

    {
      "id": 711,
      "manufacturer": "bmw",
      "model": "X5",
      "seats": 5,
      "drivers": [
       {
        "id": "23",
        "name": "Stefan Jauker",
        "links": [
         {
         "rel": "self",
         "href": "/api/v1/drivers/23"
        }
       ]
      }
     ]
    }
    

    【讨论】:

    • 不幸的是,它是我必须与之交互的遗留应用程序。否则,我再同意不过了!
    • 知道了...所以,读取这个 JSON 的客户端必须知道这个循环依赖,并在解码 JSON 时设置引用。
    猜你喜欢
    • 2011-02-07
    • 1970-01-01
    • 2017-05-12
    • 1970-01-01
    • 2011-10-04
    • 1970-01-01
    • 1970-01-01
    • 2013-02-03
    • 1970-01-01
    相关资源
    最近更新 更多