Подтвердить что ты не робот

Параметры доктрины каскада для OneToMany

Мне нелегко осмыслить руководство "Doctrine manual" объяснение каскадных операций и нужно, чтобы кто-то помог мне понять варианты в условия простого отношения ManyToOne.

В моем приложении у меня есть таблица/объект с именем Article, который имеет поле внешнего ключа, ссылающееся на поле id в таблице/объекте с именем Topic.

Когда я создаю новую статью, я выбираю тему из выпадающего меню. Это вставляет целое число в поле "topic_id" внешнего ключа в таблице "Статьи".

У меня есть ассоциация $topic, созданная в объекте Article следующим образом:

/**
 * @ManyToOne(targetEntity="Topic")
 * @JoinColumn(name="topic_id", referencedColumnName="id", nullable=false)
 */
private $topic;

У объекта темы нет взаимной аннотации относительно объекта Article. Темы не заботятся о том, что статьи ссылаются на них, и ничего не должно произойти с темой, когда статья, ссылающаяся на тему, удаляется.

Поскольку я не указываю каскадную операцию в объекте Article, Doctrine выдает ошибку при попытке создать новую статью: "Новый объект был найден через отношения, которые не были настроены на каскадное сохранение операций. Явно сохраняю новый объект или сконфигурировать каскадные операции с сохранением отношения."

Итак, я знаю, что мне нужно выбрать каскадную операцию для включения в объект Article, но как узнать, какую операцию выбрать в этой ситуации?

Из прочитанного руководства Doctrine, "отсоединить" звучит как правильный вариант. Но изучение других подобных вопросов здесь и здесь заставляет меня думать, что я хочу использовать вместо этого "persist".

Может ли кто-нибудь помочь мне понять, что "сохраняются", "удалять", "сливать" и "отделять" означать в терминах простого отношения ManyToOne, подобного тому, которое я описал?

4b9b3361

Ответ 1

В документации Doctrine2 "9.6. Transitive persistence/Cascade Operations" есть несколько примеров того, как вы должны настраивать свои сущности, чтобы при сохранении статьи $$ topic также будет сохраняться. В вашем случае я бы предложил эту аннотацию для объекта Subject:

/**
 * @OneToMany(targetEntity="Article", mappedBy="topic", cascade={"persist", "remove"})
 */
 private $articles;  

Недостатком этого решения является то, что вы должны включать $articles collection в объект Subject, но вы можете оставить его закрытым без getter/setter.

И как упоминал @kurt-krueckeberg, вы должны передать реальный объект Subject при создании новой статьи, то есть:

$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

Удачи!

Ответ 2

Если у вас есть однонаправленная связь @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;

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