我很难理解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”听起来就像是正确的选择。但研究其他人的类似问题here和here会让我觉得我想用“坚持”代替。
任何人都可以帮助我理解“坚持”,“删除”,“合并”和“分离”对于我所描述的简单ManyToOne关系的意义吗?
答案 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;
我希望这会有所帮助。