Доктрина "Новая сущность была найдена через связь"

Прежде всего, я хочу сказать, что прочитал все документы и разобрал это много, прежде чем публиковать этот вопрос. Я знаю, что означает эта ошибка (нерезидентный объект в отношениях)

Я получаю эту ошибку, когда думаю, что не должен ее получать.

У меня есть соотношение OneToMany Двунаправленное:

Class Channel
{
    /** 
    * @ORM\OneToMany(targetEntity="Step", mappedBy="channel", cascade={"all"}, orphanRemoval=true)
    * @ORM\OrderBy({"sequence" = "ASC"})
    */
    protected $steps;
}

Class Step
{
    /** 
    * @ORM\ManyToOne(targetEntity="Channel", inversedBy="steps")
    */
    protected $channel;
}

Один Channel может иметь много Step, а сторона-владелец Channel. После того, как я обновился с Doctrine 2.4 до 2,5, я получаю эту ошибку:

Doctrine\ORM\ORMInvalidArgumentException: найден новый объект через связь "Компания\MyBundle\Entity\Step # channel", которая не настроен на каскадное сохранение операций для объекта

почему он даже находит новые отношения с обратной стороны? Здесь мой код:

$channel = new Channel();
$step = new Step();
$channel->addStep($step);
$em->persist($channel);
$em->flush();

Спасибо!

Ответ 1

Вы правы: Доктрина выглядит только для изменений в собственной стороне, но вы ошибаетесь: владеющая сторона ваших отношений Step, а не Channel.

Почему шаг на стороне? Потому что это объект, который имеет внешний ключ. Даже документация Doctrine говорит вам

Собственная сторона должна использовать атрибут inversedBy OneToOne, ManyToOne или ManyToMany. Атрибут inverseedBy содержит имя поля ассоциации на обратной стороне.

Возможные решения:

  • Попробуйте инвертировать каскадные операции, помещая cascade={"all"} в объект Step (вы уверены, что все является правильным выбором?)

  • Явным образом сохраняю оба объекта:

    $channel = new Channel();
    $step = new Step();
    $channel->addStep($step);
    $em->persist($channel);
    $em->persist($step);
    $em->flush();
    

    здесь вы можете прочитать, почему второй способ, представленный здесь, тоже хорош.

Ответ 2

Вы пытаетесь сохранить $channel, но внутри этого объекта есть Step. Итак, в Doctrine теперь у вас есть 2 объекта, которые поставлены в очередь для вставки. Затем объекты Doctrine упорядочиваются в порядке, где сначала Step, потому что у него есть channel_id внешний ключ (который теперь пуст). Doctrine try persist this entity, и когда он понимает, что channel_id пуст, он видит, что правила каскада сохраняются. Он не видит никаких каскадных правил и бросает вам это исключение.