web-dev-qa-db-fra.com

Doctrine Options de cascade pour OneToMany

J'ai du mal à comprendre le Doctrine manuel explication des opérations en cascade et j'ai besoin de quelqu'un pour m'aider à comprendre les options en termes d'une simple relation ManyToOne.

Dans ma demande, j'ai une table/entité nommée Article qui a un champ de clé étrangère référençant le champ 'id' dans une table/entité nommée Topic.

Lorsque je crée un nouvel article, je sélectionne le sujet dans un menu déroulant. Cela insère un entier dans le champ de clé étrangère "topic_id" de la table Article.

J'ai l'association $ topic configurée dans l'entité Article comme ceci:

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

L'entité Sujet n'a pas d'annotation réciproque concernant l'entité Article. Les sujets ne se soucient pas des articles qui les référencent et rien ne doit arriver à un sujet lorsqu'un article qui fait référence au sujet est supprimé.

Étant donné que je ne spécifie pas l'opération en cascade dans l'entité Article, Doctrine génère une erreur lorsque j'essaie de créer un nouvel article: "Une nouvelle entité a été trouvée via une relation qui n'a pas été configurée pour opérations persistantes en cascade. Persistez explicitement la nouvelle entité ou configurez les opérations persistantes en cascade sur la relation. "

Je sais donc que je dois choisir une opération en cascade à inclure dans l'entité Article, mais comment savoir quelle opération choisir dans cette situation?

En lisant le manuel Doctrine, "détacher" semble être la bonne option. Mais rechercher les questions similaires des autres ici et ici me fait penser Je veux plutôt utiliser "persist".

Quelqu'un peut-il m'aider à comprendre ce que "persister", "supprimer", "fusionner" et "détacher" signifie en termes de simple relation ManyToOne comme celle que j'ai décrite?

38
cantera

Dans la documentation Doctrine2 " 9.6. Transitive persistence/Cascade Operations " il y a peu d'exemples de la façon dont vous devez configurer vos entités afin que lorsque vous persistez $ article, le $ topic soit également conservé. Dans votre cas, je suggère cette annotation pour l'entité Topic:

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

L'inconvénient de cette solution est que vous devez inclure la collection $ articles à l'entité Topic, mais vous pouvez la laisser privée sans getter/setter.

Et comme @ kurt-krueckeberg l'a mentionné, vous devez transmettre la véritable entité Topic lors de la création d'un nouvel article, à savoir:

$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

Bonne chance!

28
Sergiy Sokolenko

Si vous avez une association unidirectionnelle @OneToMany, comme celle décrite dans la section 6.10 de la référence Doctrine, alors vous avez probablement oublié de conserver le sujet avant d'appeler flush. Ne définissez pas la clé primaire topic_id dans l'article. Définissez plutôt l'instance de sujet.

Par exemple, étant donné les entités Article et Sujet comme celles-ci:

<?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;}
}

Après avoir généré le schéma:

# doctrine orm:schema-tool:create

votre code pour persister ces entités ressemblerait à quelque chose de ce

//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;

J'espère que ça aide.

0
Kurt Krueckeberg