基本上,我有两个表(Article和Tag),我想使多对多(一篇文章可以有许多标签,一个标签可以分配给许多文章)关系与一些额外的属性。我可以在Doctrine2中通过将其分解为两个独立的关系(一对多,多对一)和一个带有我的额外属性的关系表ArticleTag来编写此内容。
我的问题是,我不知道我是否可以使Doctrine2也为我创建连接表实体。我的意思是当我调用:
$article = /* create new article, etc... */
$tag = /* create new tag, etc... */
$article->addTag($tag);
$em->persist($article);
$em->flush();
It DOES在数据库中创建Article和Tag实体,但是It DOES NOT创建ArticleTag实体(换句话说,它不创建Article和Tag之间的连接)。我可以自己创建它,但我宁愿依赖Doctrine2。
当然,当我使用由Doctrine2生成的标准连接表时,它工作得很好,但我需要那些额外的属性。
有人有什么想法吗?还是我真的要手工做?
编辑:源代码
/**
* @ORMEntity
*/
class Article {
/**
* @ORMId
* @ORMGeneratedValue
* @ORMColumn(type="integer")
*/
protected $id;
/**
* @ORMOneToMany(targetEntity="Tag", mappedBy="article", cascade={"persist"})
* @ORMJoinTable(name="ArticleTag", joinColumns={@ORMJoinColumn(name="article_id", referencedColumnName="id")})
* )
*/
protected $tags;
...
}
/**
* @ORMEntity
*/
class ArticleTag {
/**
* @ORMId
* @ORMGeneratedValue
* @ORMColumn(type="integer")
*/
protected $id;
/**
* @ORMManyToOne(targetEntity="Article")
*/
private $article;
/**
* @ORMManyToOne(targetEntity="Tag")
* @ORMJoinColumn(name="tag_id", referencedColumnName="id")
*/
private $tag;
/**
* @ORMColumn(type="float")
*/
protected $priority = 0.5;
}
/**
* @ORMEntity
*/
class Tag {
/**
* @ORMId
* @ORMGeneratedValue
* @ORMColumn(type="integer")
*/
protected $id;
/**
* @ORMColumn(type="string", length=32)
*/
protected $name;
}
没有办法自动做到这一点,但您可以将Article
类上的addTag
方法更改为如下内容:
public function addTag(Tag $tag, $priority)
{
$articleTag = new ArticleTag();
$articleTag->setTag($tag);
$articleTag->setArticle($this);
$articleTag->setPriority($priority);
$this->addArticleTag($articleTag);
return $this;
}
这样,您可以集中代码并隐藏ArticleTag
条目的创建。作为额外的解释,下面是这个逻辑背后的推理:
在Doctrine看来,一个类代表一个实体源,该类的每个实例代表一个实体。在简单的多对多表中,多对多表不是实体。事实上,它仅仅是两个实体之间的关系,这就是为什么Doctrine允许您绕过这个逻辑,并且如果它只有外键,则不需要ArticleTag
实体。
但是,一旦向该表添加了额外的元数据,它就不再是关系表了。我曾与许多看法不同的人讨论过这个问题,但事实并非如此。是的,它定义了实体1和实体2是相关的,但是这个附加列定义了关联所需的附加元数据。因此,它是一个独立的实体,必须这样反映。
我为此挣扎了很长一段时间,直到我最终添加了上面展示的代码。
我的实体可以连接文章与他们的标签(主题在我的模式)没有任何连接实体,你需要连接实体的任何特定原因吗?
使用$article->getSubjects()->add($subject);
实体/**
* @ORMEntity(repositoryClass="FamArticle")
* @ORMTable(name="Article")
*/
class Article{
/*StartProtected*/
protected $links = array();
public function __construct()
{
$this->subjects = new DoctrineCommonCollectionsArrayCollection();
}
/**
* @ORMManyToMany(targetEntity="Subject")
* @ORMJoinTable(name="Article_to_Subject",
* joinColumns={@ORMJoinColumn(name="articleId", referencedColumnName="articleId")},
* inverseJoinColumns={@ORMJoinColumn(name="subjectId", referencedColumnName="subjectId")}
* )
*/
protected $subjects;
/**
*
* @return DoctrineCommonCollectionsArrayCollection
*/
public function getSubjects()
{
return $this->subjects;
}
public function removeSubjects(){ $this->subjects = new DoctrineCommonCollectionsArrayCollection(); return $this; }