具有多对多关系的 Symfony 5 对象序列化超时

Posted

技术标签:

【中文标题】具有多对多关系的 Symfony 5 对象序列化超时【英文标题】:Symfony 5 Object Serialization with ManyToMany Relation Times Out 【发布时间】:2021-02-19 16:09:33 【问题描述】:

在我的 Symfony 5 应用程序中,我有一个实体类 Product,它有两个属性 $categories$bundles。产品类与这两个属性都具有多对多关系。当我注释掉任一属性时,产品序列化工作完美。但如果这两个属性都存在,则序列化超时。

产品类的代码摘录。

class Product

    /**
     * @ORM\ManyToMany(targetEntity=ProductBundle::class, mappedBy="products")
     */
    private $productBundles;

    /**
     * @ORM\ManyToMany(targetEntity=Category::class, mappedBy="products")
     * @MaxDepth(1)
     */
    private $categories;


序列化代码如下。

    $products = $productRepository->findBySearchQuery($name);
    $productsJson = $serializerInterface->serialize($products, 'json', [
        ObjectNormalizer::CIRCULAR_REFERENCE_HANDLER => function ($object) 
            return $object->getId();
        
    ]);

我已经尝试使用在其他一些 *** 答案和 @MaxDepth 上建议的 @ORM/JoinTable 注释,但没有运气。如果任何属性被注释掉,代码就可以工作。非常感谢您对此提供任何建议。

【问题讨论】:

不知道您是否尝试过...但是...“仅当序列化程序上下文的 AbstractObjectNormalizer::ENABLE_MAX_DEPTH 键设置为 true 时才进行检查。”来源:symfony.com/doc/current/components/… ...我会说您正在尝试序列化“太多”(内存/运行时量)并且可能正在导出整个产品数据库? ^^ @Jakumi 我的数据库中只有 20 个产品,所以我认为可以序列化,深度部分也没有帮助,但感谢您指出。但是,当我只返回产品名称时,它就开始起作用了。迷茫... 【参考方案1】:

好的,20 个产品实际上并不多。所以我猜如果你让关系不受阻碍地序列化,你会一遍又一遍地输出相同的对象。

我实际上不知道如何使用序列化程序可靠地实现这一点。但是标准的方法可能就足够了。我喜欢像这样在您的实体上通过JsonSerializable 接口进行序列化(为简洁起见,省略ORM 内容):

class Product implements \JsonSerializable 
    public $name;
    public $categories; // relation

    // getters + setters omitted

    // this implements \JsonSerializable
    public function jsonSerialize() 
        return [
            'name' => $this->name,
            'categories' => array_map(function($category) 
                 return $category->jsonSerializeChild();
            , $this->categories),
        ];
    

    // this function effectively stops recursion by leaving out relations
    public function jsonSerializeChild() 
        return [
            'name' => $this->name,
        ];
    

如果您在所有实体上实现此功能,您可以非常有效地将序列化深度限制为两个(即“基础”实体及其连接的实体)。

此外,如果您将 序列化为 JSON,则如果定义了 JsonSerializable 接口,则 symfony 序列化程序将使用该接口。显然,这并不像一些花哨的基于注释的序列化或“智能”序列化器那样优雅,实际上可以停止......但它可能会更好......

【讨论】:

您可能对序列化程序循环一遍又一遍地处理具有关系的对象是正确的。感谢您的回答,但我在 Symfony 中找到了一种内置方式来实现这一点,而无需编写我自己的 jsonSerialize 和 jsonSerializeChild 函数。如果对任何人有帮助,我会在这里发布答案。 绝对可以! ;o)【参考方案2】:

@Jakumi 指出,序列化程序循环遍历对象属性 $categories$bundles。我通过使用序列化组避免了这种情况。

产品类别

class Product

    /**
     * @ORM\ManyToMany(targetEntity=ProductBundle::class, mappedBy="products")
     * @Groups("product_listing:read")
     */
    private $productBundles;

    /**
     * @ORM\ManyToMany(targetEntity=Category::class, mappedBy="products")
     * @Groups("product_listing:read")
     */
    private $categories;


类别类

class Category

    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     * @Groups("product_listing:read")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=255)
     * @Groups("product_listing:read")
     */
    private $name;

对序列化程序的调用

$products = $productRepository->findBySearchQuery($name);
$productsJson = $serializerInterface->serialize($products, 'json', ['groups' => 'product_listing:read']);

我希望这对将来的人有所帮助。

【讨论】:

以上是关于具有多对多关系的 Symfony 5 对象序列化超时的主要内容,如果未能解决你的问题,请参考以下文章

Symfony 固定装置和多对多关系(学说)

Symfony 3.4 - 如果在多对多关系上不存在,则持续存在

在多对多关系对象django的对象中获取null

Django:通过参数序列化具有多对多关系的模型

Django:对象需要具有字段“...”的值才能使用这种多对多关系

Symfony 查询生成器(多对多关系)