OneToMany的Doctrine Cascade选项

时间:2011-10-10 06:41:00

标签: doctrine-orm cascade

我很难理解Doctrine手册的explanation级联操作,需要有人帮助我理解简单的ManyToOne关系中的选项。

在我的应用程序中,我有一个名为Article的表/实体,它有一个外键字段,引用名为Topic的表/实体中的'id'字段。

当我创建新文章时,我从下拉菜单中选择主题。这会在Article表的'topic_id'外键字段中插入一个整数。

我在Article实体中设置了$ topic关联,如下所示:

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

主题实体没有关于Article实体的任何往复注释。当参考主题的文章被删除时,主题不关心什么文章引用它们,并且不需要在主题中发生任何事情。

因为我没有在Article实体中指定级联操作,所以当我尝试创建新文章时,Doctrine会抛出错误:“通过未配置为级联持久操作的关系找到新实体。显式持续新实体或配置级联持久性操作关系。“

所以我知道我需要选择一个级联操作来包含在Article实体中,但是我怎么知道在这种情况下选择哪个操作呢?

从阅读Doctrine手册开始,“detach”听起来就像是正确的选择。但研究其他人的类似问题herehere会让我觉得我想用“坚持”代替。

任何人都可以帮助我理解“坚持”,“删除”,“合并”和“分离”对于我所描述的简单ManyToOne关系的意义吗?

2 个答案:

答案 0 :(得分:29)

在Doctrine2文档“9.6. Transitive persistence / Cascade Operations”中,很少有关于如何配置实体的示例,以便在保留$ article时,$ topic也会保留。在你的情况下,我建议为Topic实体注释:

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

此解决方案的缺点是您必须将$ articles集合包含在Topic实体中,但您可以将其保留为私有而不使用getter / setter。

正如@ kurt-krueckeberg所提到的,你必须在创建新文章时传递真正的主题实体,即:

$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
祝你好运!

答案 1 :(得分:0)

如果你有一个@OneToMany单向关联,就像Doctrine Reference第6.10节中描述的那样,那么你很可能忘记在调用flush之前保留Topic。不要在Article中设置topic_id主键。而是设置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;

我希望这会有所帮助。