Варианты каскада доктрин для OneToMany
Мне трудно разобраться в объяснениях каскадных операций в руководстве по Doctrine, и мне нужен кто-то, чтобы помочь мне понять варианты с точки зрения простых отношений ManyToOne.
В моем приложении у меня есть таблица / сущность с именем Article, которая имеет поле внешнего ключа, ссылающееся на поле 'id' в таблице / сущности с именем Topic.
Когда я создаю новую статью, я выбираю тему из выпадающего меню. Это вставит целое число в поле внешнего ключа topic_id в таблице Article.
Я установил ассоциацию $ topic в сущности Article следующим образом:
/**
* @ManyToOne(targetEntity="Topic")
* @JoinColumn(name="topic_id", referencedColumnName="id", nullable=false)
*/
private $topic;
У сущности Topic нет обратной аннотации относительно сущности Article. Темам не важно, какие статьи ссылаются на них, и с темой ничего не должно случиться, когда удаляется статья, ссылающаяся на тему.
Поскольку я не указываю каскадную операцию в сущности Article, Doctrine выдает ошибку, когда я пытаюсь создать новую Article: "В связи, которая не была сконфигурирована для каскадных сохраняемых операций, была обнаружена новая сущность. Явно сохраняйте новую сущность или настроить каскадные постоянные операции над отношениями."
Итак, я знаю, что мне нужно выбрать каскадную операцию для включения в сущность Article, но как мне узнать, какую операцию выбрать в этой ситуации?
Из прочтения руководства по доктрине "отсоединение" звучит как правильный вариант. Но изучение подобных вопросов других здесь и здесь заставляет меня думать, что я хочу использовать вместо этого "постоянство".
Может ли кто-нибудь помочь мне понять, что означают "сохраняться", "удалять", "объединять" и "отделять" в терминах простых отношений ManyToOne, подобных описанным мной?
2 ответа
В документации Doctrine2 " 9.6. Транзитивное постоянство / каскадные операции" есть несколько примеров того, как вы должны сконфигурировать свои сущности, чтобы при сохранении $ article также сохранялась тема $. В вашем случае я бы предложил эту аннотацию для объекта Тема:
/**
* @OneToMany(targetEntity="Article", mappedBy="topic", cascade={"persist", "remove"})
*/
private $articles;
Недостатком этого решения является то, что вы должны включить коллекцию $ article в сущность Topic, но вы можете оставить ее приватной без getter/setter.
И, как упоминал @kurt-krueckeberg, вы должны передать реальную сущность Topic при создании новой Article, а именно:
$topic = $em->getRepository('Entity\Topic')->find($id);
$article = new Article($topic);
$em->persist($article);
$em->flush();
// perhaps, in this case you don't even need to configure cascade operations
Удачи!
Если у вас есть однонаправленная ассоциация @OneToMany, как описано в разделе 6.10 Справочника по доктрине, то, скорее всего, вы забыли сохранить тему перед вызовом сброса. Не устанавливайте первичный ключ topic_id в статье. Вместо этого установите экземпляр темы.
Например, данные сущности Article и Topic, подобные этим:
<?php
namespace Entities;
/**
@Entity
@Table(name="articles")
*/
class Article {
/**
* @Id
* @Column(type="integer", name="article_id")
* @GeneratedValue
*/
protected $id;
/**
* @Column(type="text")
*/
protected $text;
/**
* @ManyToOne(targetEntity="Topic", inversedBy="articles")
* @JoinColumn(name="topic_id", referencedColumnName="topic_id")
*/
protected $topic;
public function __construct($text=null)
{
if (!is_null($text)) {
$this->text = $text;
}
}
public function setArticle($text)
{
$this->text = $text;
}
public function setTopic(Topic $t)
{
$this->topic = $t;
}
}
<?php
namespace Entities;
/**
@Entity
@Table(name="topics")
*/
class Topic {
/**
* @Id
* @Column(type="integer", name="topic_id")
* @GeneratedValue
*/
protected $id;
public function __construct() {}
public function getId() {return $this->id;}
}
После создания схемы:
# doctrine orm:schema-tool:create
Ваш код для сохранения этих объектов будет выглядеть как-то так
//configuration omitted..
$em = \Doctrine\ORM\EntityManager::create($connectionOptions, $config);
$topic = new Entities\Topic();
$article1 = new Entities\Article("article 1");
$article2 = new Entities\Article("article 2");
$article1->setTopic($topic);
$article2->setTopic($topic);
$em->persist($article1);
$em->persist($article2);
$em->persist($topic);
try {
$em->flush();
} catch(Exception $e) {
$msg= $e->getMessage();
echo $msg . "<br />\n";
}
return;
Надеюсь, это поможет.