ContextErrorException: Неопределенный индекс при использовании составного ключа для ассоциаций доктрины с сущностями Symfony 3

У меня есть два объекта, где каждый Product может иметь связанные с ним объекты oneToMany Aspect.

Поскольку таблица «Продукты» очень большая, я использую bigint для ее идентификатора, и, следовательно, я пытаюсь создать составной ключ для Aspect, чтобы использовать идентификатор продукта и smallint (который я пытаюсь увеличить с помощью Product#aspectsCount). Однако я получаю исключение ContextErrorException:

Примечание: Неопределенный индекс: аспект

Мои сущности такие, как показано ниже (первоначально я пробовал indexBy="id") в надежде использовать числовой идентификатор Aspect, но я не могу заставить это работать, поэтому использовал 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...
}

person Bendy    schedule 02.01.2017    source источник
comment
Notice: Undefined index: aspect где эта ошибка   -  person Waqar Haider    schedule 09.01.2017
comment
Я использую FOSRestBundle, и эта ошибка возвращается в JSON, когда я запрашиваю маршрут, использующий объект Product.   -  person Bendy    schedule 09.01.2017
comment
Являются ли они вашими полными сущностями? если нет, опубликуйте их также. И также опубликуйте свой код FOSBundle для вставки. может и я узнаю что-то новое   -  person Waqar Haider    schedule 09.01.2017
comment
потому что я вижу $this->setCreateDT(new \Datetime); $this->setUpdateDT(new \Datetime); и `$product-›setAspectsCount($product-›getAspectsCount()+1);`, но они нигде не определены   -  person Waqar Haider    schedule 09.01.2017
comment
Я «к сожалению» в отпуске, поэтому не могу получить полный код для публикации, но это свернутый код, который вызывает у меня проблему. Упомянутый вами код getAspectsCount()+1 (и связанный с ним) используется для хранения счетчика в каждом продукте, поэтому каждый новый аспект для элемента имеет увеличенное целое число для идентификатора.   -  person Bendy    schedule 10.01.2017


Ответы (2)


в объекте продукта измените аннотации $ Aspets на это

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

Затем вам нужно обновить схему базы данных

person G. Mansour    schedule 12.01.2017
comment
Я отметил этот ответ толстым пальцем вместо того, чтобы присудить свою награду (!). Я не могу сейчас поднять флаг для администратора, так как я уже (случайно) отметил его. Спасибо за решение проблемы. Может ли администратор исправить (и удалить этот комментарий, если это возможно)? - person Bendy; 13.01.2017

Я предполагаю, что проблема возникает, когда вы делаете $this->aspects[$name] = $aspect; Это ArrayCollection, а не массив, и хотя в большинстве случаев он работает как единое целое, вы не можете установить имя для элемента в коллекции. Кроме того, ArrayCollections являются более сложными объектами, а также позволяют запрашивать и упорядочивать их. Просто вызовите $this->aspects->add($aspect);

В соответствии с вашим последним вопросом вы можете определить несколько столбцов соединения при указании отношения manyToOne, поэтому вы просто добавляете определения для нескольких столбцов вместо одного в случае, если вам нужно связать объект с составным ключом.

Наконец, я хотел бы отметить одну вещь из моего личного опыта: многие функции, которые также встроены в языки программирования и программы, часто добавляют ненужную сложность к программному обеспечению, которое вы пишете. Если у вас есть возможность (а в большинстве случаев она у вас есть), вам следует избегать таких вещей, как составные ключи/наследование/и т.д.... Часто оказывается, что они не приносят реальной пользы, но могут стать кошмаром для работы в будущем. Бывают случаи, когда без них не обойтись, но их очень мало.

В вашем случае вы уже тратите время на размышления о том, как этот составной ключ будет работать, когда вам нужно добавить отношения (также составные ключи немного менее эффективны, когда дело доходит до запросов), но даже если вы не использовали составной ключ (просто обычный идентификатор объекта аспекта), вызов метода getAspects() по-прежнему предоставит вам набор массивов, упорядоченный по идентификатору (по умолчанию это можно изменить), поэтому вы все равно сможете нумеровать элементы и порядок останется прежним. Даже если бы вам пришлось реализовать что-то вроде возможности для пользователей изменять порядок элементов, вы все равно могли бы просто добавить еще одно поле порядка в сущность и не тратить ни секунды на размышления о том, как здесь составной ключ будет взаимодействовать с остальной частью системы. . И опять же, эти проблемы не исчезают, только потому, что вы находите решения сейчас, они также будут усложнять программу и в будущем.

person grssn    schedule 11.01.2017
comment
Спасибо - очень хороший момент. Другой ответ устранил мою непосредственную проблему, но я собираюсь сделать шаг назад и пересмотреть составные ключи, как вы предложили. - person Bendy; 13.01.2017