Варианты каскада доктрин для 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;

Надеюсь, это поможет.

Другие вопросы по тегам