【问题标题】:ContextErrorException: Undefined Index when using composite key for doctrine associations with Symfony 3 entitiesContextErrorException:使用组合键与 Symfony 3 实体进行教义关联时未定义索引
【发布时间】:2017-01-02 21:47:40
【问题描述】:

我有两个实体,其中每个 Product 可以有 oneToMany Aspect 实体与之关联。

由于 Products 表非常大,我使用 bigint 作为它的 ID,因此,我正在尝试为 Aspect 构建一个复合键以使用 Product ID 和 smallint (我试图用Product#aspectsCount 增加)。但是,我收到了 ContextErrorException:

注意:未定义索引:方面

我的实体如下(我最初尝试 indexBy="id") 是为了使用 Aspect 的数字 ID,但我似乎也无法使其正常工作,因此使用下面的 name与我在网上阅读的示例更一致):

产品实体

class Product
{
    /**
     * @ORM\Column(type="bigint", options={"unsigned"=true})
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\OneToMany(targetEntity="Aspect", mappedBy="product", cascade={"all"}, indexBy="name")
     */
    private $aspects;

    /**
     * @ORM\Column(name="aspectsCount", type="smallint", options={"unsigned"=true}, nullable=false)
     */
    private $aspectsCount;

    public function __construct()
    {
        $this->aspects = new ArrayCollection();

        $this->setCreateDT(new \Datetime);
        $this->setUpdateDT(new \Datetime);
        $this->aspectsCount = 0;
    }


    /**
     * Add aspect
     *
     * @param \AppBundle\Entity\Aspect $aspect
     *
     * @return product
     */
    public function addAspect($name)
    {
        $aspect = new Aspect($this, $name);
        $this->aspects[$name] = $aspect;

        return $this;
    }

    /**
     * Remove aspect
     *
     * @param \AppBundle\Entity\Aspect $aspect
     */
    public function removeAspect(\AppBundle\Entity\Aspect $aspect)
    {
        $this->aspects->removeElement($aspect);
        $this->setAspectsCount($this->aspectsCount-1);
    }
}

方面实体

class Aspect
{
    /**
     * @ORM\Id
     * @ORM\ManyToOne(targetEntity="Product", inversedBy="aspects") 
     * @ORM\JoinColumn(name="product_id", referencedColumnName="id")
     */
    private $product;

    /**
     * @ORM\Id
     * @ORM\Column(type="smallint", options={"unsigned"=true}, nullable=false)
     */
    private $id;

    /**
     * @ORM\Column(name="name", type="text")
     */
    private $name;

    public function __construct($product, $name)
    {
        $product->setAspectsCount($product->getAspectsCount()+1);

        $this->product = $product;
        $this->id = $product->getAspectsCount();
        $this->name = $name;
    }

 }

通过扩展,如果另一个表应该存在于“下方”Aspect,如何建立这样的关联? Doctrine 会在内部处理复合键还是我需要执行以下操作:

class Aspect_subtype
{
    /**
     * @ORM\Id
     * @ORM\ManyToOne(targetEntity="Product")   
     * @ORM\JoinColumn(name="product_id", referencedColumnName="id")
     */
    private $product;

    /**
     * @ORM\Id
     * @ORM\ManyToOne(targetEntity="Aspect")    
     * @ORM\JoinColumn(name="aspect_id", referencedColumnName="id")
     */
    private $aspect;

    /**
     * @ORM\Id
     * @ORM\Column(type="smallint", options={"unsigned"=true}, nullable=false)
     */
    private $id;

    /**
     * @ORM\Column(name="name", type="text")
     */
    private $name;

// etc...
}

【问题讨论】:

  • Notice: Undefined index: aspect 哪里出错了
  • 我正在使用 FOSRestBundle,当我请求使用 Product 实体的路由时,此错误会在 JSON 中返回
  • 他们是你的完整实体吗?如果不发布它们以及发布您的 FOSBundle 代码以进行插入。我也可以学到一些新东西
  • 因为我看到 $this->setCreateDT(new \Datetime); $this->setUpdateDT(new \Datetime); 和 `$product->setAspectsCount($product->getAspectsCount()+1);` 但它们没有在任何地方定义
  • 我“很遗憾”正在度假,所以无法发布完整的代码 - 但这是给我带来问题的简化代码。您提到的getAspectsCount()+1(及相关)代码用于在每个产品中存储一个计数器,以便项目的每个新方面都有一个递增的 ID 整数

标签: doctrine-orm symfony composite-primary-key


【解决方案1】:

在产品实体中将$Aspets的注解改成这个

     /**
     *@ORM\ManyToOne(targetEntity="Aspect")
     *@ORM\JoinColumn(name="Client", referencedColumnName="product_id",onDelete="CASCADE")
     */
    private $aspects;

那么你需要更新你的数据库架构

【讨论】:

  • 我用胖手指标记了这个答案,而不是奖励我的赏金(!)。我现在无法向管理员提出标志,因为我已经(不小心)标记了它。感谢您解决问题。请管理员修复(如果可能,请删除此评论)?
【解决方案2】:

我猜当你执行 $this->aspects[$name] = $aspect; 时会出现问题 它是一个 ArrayCollection,而不是一个数组,即使在大多数情况下它的工作方式类似,您也不能为集合中的项目设置名称。除了 ArrayCollections 是更复杂的对象,还允许查询和排序它们。只需调用 $this->aspects->add($aspect);

根据您的最后一个问题,您可以在指定 manyToOne 关系时定义多个连接列,因此您只需为多个列添加定义,而不是在这种情况下,您需要与具有复合的实体相关联键。

最后,我想从我的个人经验中指出一件事:编程语言和程序中内置的许多功能通常会给您正在编写的软件增加不必要的复杂性。如果您有能力(并且大部分时间都这样做),则应该回避诸如复合键/继承/等之类的事情。很多时候,它们被证明并没有提供真正的好处,但将来可能会成为一场噩梦。在某些情况下,您离不开它们,但这种情况很少见。

在您的情况下,您已经在浪费时间考虑当您需要添加关系时这个复合键将如何工作(在查询时复合键的性能也稍差),即使您没有使用复合键键(只是方面实体上的常规 id),调用 getAspects() 方法仍会为您提供按 ID 排序的数组集合(默认情况下。可以更改),因此您仍然可以编号项目和订购将保持不变。即使您必须实现用户更改元素顺序的功能,您仍然可以简单地向实体添加另一个顺序字段,而无需花一秒钟时间考虑这里的复合键将如何与系统的其余部分交互.再说一遍,这些问题并没有消失,只是因为你现在找到了解决方案,它们也会在未来增加程序的复杂性。

【讨论】:

  • 谢谢 - 非常好。另一个答案解决了我的直接问题,但我将退后一步,按照您的建议重新考虑复合键
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多