【问题标题】:symfony 3.4 - ManyToOne can't access to the data of an entitysymfony 3.4 - ManyToOne 无法访问实体的数据
【发布时间】:2019-05-02 18:51:51
【问题描述】:

我有一个实体叫 Category,另一个叫 Product,中间一个叫 CategoryProduct。

  • 我在 Category 和 CategoryProduct 之间有一个关系 OneToMany: @ORM\OneToMany(targetEntity="CategoryProduct", mappedBy="Catego", fetch="EAGER") 与 CategoryProduct 类中的 inversedBy(在 $catego 上)。
  • 我在 CategoryProduct 和 Product 之间有 OneToOne 关系:@ORM\OneToOne(targetEntity="Product", inversedBy="Category") 与 Product 类中的 inversedBy(在 $category 上)。

在我的 CategoryController 中,我有一个这样的功能:

public function getCategoryAction(Request $request)
{
    $category = $this->get('doctrine.orm.entity_manager')
                 ->getRepository('AppBundle:Category')
                 ->findAll();
    return new JsonResponse($category);
}

返回给实体Category的集合,但是“子实体”Product是空的。当我在 Symfony 中检查 Token for debbug 时,我检查了 Doctrine 部分并且查询工作完美,数据加载它只是在我的返回中没有。我可以使用$category->getProduct() 访问数据(它为我提供了我想要的类别的产品链接集合),但我的产品子类仍然是空的。有谁知道为什么?

感谢您的帮助。

【问题讨论】:

  • 尝试运行php bin/console doctrine:schema:validate --skip-sync,看看是否有任何映射错误。 `
  • ...或doctrine:shema:update
  • 除了 Carl 对验证架构的有用建议:您确定每个产品只能有一个 CategoryProduct 吗?为什么首先使用“中产阶级”? "inversedBy="Category"" 意味着,您需要在 Product 类上有一个 $Category 属性。但它实际上不是一个类别,它是一个 CategoryProduct。
  • 我已经尝试了架构验证/更新,没有问题。我需要中间的类来获取一些我无法保存在其他任何地方的信息,属性的名称不相关,可以随意调用。无论如何感谢您的帮助

标签: php symfony doctrine symfony-3.4


【解决方案1】:

从一开始就解决当前的问题是典型的 Doctrine 水化问题。

默认情况下,Doctrine 会延迟加载关系,这意味着最初 Doctrine 提供了一个代理集合,其中不包含任何元素,并且仅在以某种方式访问​​它们时才加载实际元素(例如,当使用像 getProduct( ))。这就是为什么您的产品集合看起来是空的。

您可以通过将关联中的 fetch 属性设置为 EAGER 来轻松更改此设置:

// inside Category class
/**
 * @ManyToOne(targetEntity="Product", fetch="EAGER")
 */
 private $products;

但最终不会让您的代码正常工作,因为当您尝试对具有私有属性的对象进行 json_encode 时,您只会得到一个空的 json。您的问题的解决方案是使用自定义方式来序列化您的对象。最简单(并且可能)最好的解决方案是使用 Symfony Serializer Component。但是您应该知道,仅使用 $serializer->serialize($category, 'json'); 会引发循环引用异常。这将是因为(我猜)您还在 Product 类中持有对 Category 的引用,如下所示:

// inside Product class
/**
 * @OneToMany(targetEntity="Category")
 */
private $category;

你可以想象,Symfony 会尝试序列化一个有很多产品的类别,这个类别有很多产品......这是一个循环引用。

要绕过这个问题,你应该使用这样的序列化组:

// inside your controller, supposing you are using autowiring to inject services:

use Symfony\Component\Serializer\SerializerInterface;

public function getTariffsAction(Request $request, SerializerInterface $serializer)
{
    $category = $this->get('doctrine.orm.entity_manager')
             ->getRepository('AppBundle:Category')
             ->findAll();

    $categoryJson = $serializer->serialize($category, 'json', ['groups' => ['tariffs'] ]);

    return $this->json($categoryJson);
}

然后显式配置对象的属性,您希望像这样进入实体:

// Category.php
use Symfony\Component\Serializer\Annotation\Groups;
...
/**
 * @ORM\Id
 * @Groups({"tariffs"})
 */
protected $id;

/**
 * @ORM\Column(type="string")
 * @Groups({"tariffs"})
 */
protected $name;

/**
 * @ORM\ManyToOne(targetEntity="Product")
 * @Groups({"tariffs"})
 */
private $product;

// any other attribute you want to include

最后在您的 Product.php 中:

Product.php

/**
 * @ORM\Id
 * @Groups({"tariffs"})
 */
protected $id;

/**
 * @ORM\Column(type="string")
 * @Groups({"tariffs"})
 */
protected $productName;

// do not include the reference to the category to avoid circular reference
/**
 * @OneToMany(targetEntity="Category")
 */
private $category;

您可以在documentation 中找到有关序列化程序组件和序列化组的更多信息。

【讨论】:

  • 抱歉耽搁了,我试过你给我的方法,但是Json响应是空的,根本没有属性。通知似乎是个好主意,但我的一位同事检查并说那里没有问题......无论如何谢谢你的帮助。如果您有任何其他想法,我会听到您的声音! :)
  • 首先你应该转储你的查询结果,看看你在序列化之前实际得到了什么。
  • 如果你尝试像这样对一个对象进行json_encode,你只会得到一个空的json。尝试使用 Serializer 组件进行序列化时将创建循环引用。我将更新我的答案以使其更清楚。
  • 当我尝试 var_dump 时,我明白了你的意思,你说得对,有一个循环引用,但我无法解决组的问题,我试过了......
  • 你的问题是什么?
【解决方案2】:

用你给我的方法在我的控制器下面更新。

public function getTariffsAction(Request $request, SerializerInterface $serializer) 
{
    $category = new Category();
    $category = $this->get('doctrine.orm.entity_manager')
            ->getRepository('AppBundle:Category')
            ->findAll();
    $categoryJson = $serializer->serialize($category , 'json', ['groups' => ['tariffs'] ]);
    return $this->json($categoryJson);
}

当我转储 $category 时,我得到了一些我无法粘贴的东西,因为它太多了。使用 Postman,它会使我的计算机出现很多错误(我的一个屏幕关闭)在那之后我必须重新启动

【讨论】:

  • $categoryJson 是一个空的字符串化数组吗?您是否以某种方式缓存教义注释?也许尝试清除此缓存会有所帮助: php bin/console dictionary:cache:clear-metadata
【解决方案3】:

问题解决了,你说得对,它是循环引用,我按照你所说的用组解决了它。 (我对组使用 FOSRestBundle 比原生 symfony 方法更容易)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多