Doctrine orm ContextErrorException:使用复合键与Symfony 3实体进行条令关联时未定义索引

Doctrine orm ContextErrorException:使用复合键与Symfony 3实体进行条令关联时未定义索引,doctrine-orm,symfony,composite-primary-key,Doctrine Orm,Symfony,Composite Primary Key,我有两个实体,每个产品都可以有一个与之关联的方面实体 由于Products表非常大,我正在使用bigint作为它的ID,因此,我正在尝试为Aspect构建一个复合键,以使用Product ID和smallint(我正在尝试使用Product#aspectscont增加该键)。但是,我得到一个ContextErrorException: 注意:未定义索引:方面 我的实体如下所示(我最初尝试indexBy=“id”),希望使用Aspect的数字id,但我似乎也无法实现这一点,因此使用name与我在线

我有两个实体,每个产品都可以有一个与之关联的方面实体

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

注意:未定义索引:方面

我的实体如下所示(我最初尝试
indexBy=“id”)
,希望使用Aspect的数字id,但我似乎也无法实现这一点,因此使用
name
与我在线阅读的示例更加一致):

产品实体 方面实体 通过扩展,若另一个表应该“在”方面之下存在,那个么如何建立这样的关联呢?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...
}

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

根据上一个问题,在指定manytone关系时,可以定义多个联接列,因此只需为多个列添加定义,而不是在需要与具有复合键的实体关联的情况下添加一个

最后,我想从我的个人经历中指出一点:许多内置于编程语言和程序中的功能常常会给您正在编写的软件增加不必要的复杂性。如果你有这种能力(而且大多数时候你都有),你应该避开像复合键/继承等。通常情况下,事实证明它们并没有带来真正的好处,但在未来可能会成为一场噩梦。有些情况下你离不开它们,但这些情况很少


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

在产品实体中将$Aspets的命名改为

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

然后您需要更新您的数据库模式

注意:未定义索引:方面
该错误在哪里我使用的是FOSRestBundle,当我请求使用产品实体的路由时,该错误以JSON返回它们是您的完整实体吗?如果没有发布它们,也发布您的FOSBundle代码以供插入。我可能会学到一些新东西,因为我看到了
$this->setCreateDT(new\Datetime)$此->setUpdateDT(新建\Datetime)和`$product->setAspectScont($product->getAspectScont()+1)`但它们并没有定义在任何地方,因为我“不幸”正在度假,所以无法发布完整的代码——但这是给我带来问题的简化代码。您提到的
getAspectScont()+1
(及相关)代码用于在每个产品中存储一个计数器,以使项目的每个新特性都有一个递增整数,IDI胖手指标记此答案,而不是奖励我的赏金(!)。我现在不能向管理员升起一个标志,因为我已经(意外地)标记了它。谢谢你解决了这个问题。能否请管理员修复(并删除此评论,如果可能)?谢谢-非常好的一点。另一个答案解决了我眼前的问题,但我将后退一步,重新考虑您建议的复合键
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...
}
     /**
     *@ORM\ManyToOne(targetEntity="Aspect")
     *@ORM\JoinColumn(name="Client", referencedColumnName="product_id",onDelete="CASCADE")
     */
    private $aspects;