Doctrine2 -保存自定义连接关系表


Doctrine2 - Saving custom join relation table

基本上,我有两个表(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生成的标准连接表时,它工作得很好,但我需要那些额外的属性。

有人有什么想法吗?还是我真的要手工做?

编辑:源代码

/**
 * @ORM'Entity
 */
class Article {
    /**
     * @ORM'Id
     * @ORM'GeneratedValue
     * @ORM'Column(type="integer")
     */
    protected $id;
    /**
     * @ORM'OneToMany(targetEntity="Tag", mappedBy="article", cascade={"persist"})
     * @ORM'JoinTable(name="ArticleTag", joinColumns={@ORM'JoinColumn(name="article_id", referencedColumnName="id")})
     * )
     */
    protected $tags;
    ...
}

/**
 * @ORM'Entity
 */
class ArticleTag {
    /**
     * @ORM'Id
     * @ORM'GeneratedValue
     * @ORM'Column(type="integer")
     */
    protected $id;
    /**
     * @ORM'ManyToOne(targetEntity="Article")
     */
     private $article;
    /**
     * @ORM'ManyToOne(targetEntity="Tag")
     * @ORM'JoinColumn(name="tag_id", referencedColumnName="id")
     */
     private $tag;
    /**
     * @ORM'Column(type="float")
     */
    protected $priority = 0.5;
}

/**
 * @ORM'Entity
 */
class Tag {
    /**
     * @ORM'Id
     * @ORM'GeneratedValue
     * @ORM'Column(type="integer")
     */
    protected $id;
    /**
     * @ORM'Column(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);

实体
/**
 * @ORM'Entity(repositoryClass="'Fam'Article")
 * @ORM'Table(name="Article")
 */
class Article{
    /*StartProtected*/
        protected $links = array();
        public function __construct()
        {
            $this->subjects = new 'Doctrine'Common'Collections'ArrayCollection();
        }
        /**
         * @ORM'ManyToMany(targetEntity="Subject")
         * @ORM'JoinTable(name="Article_to_Subject",
         *      joinColumns={@ORM'JoinColumn(name="articleId", referencedColumnName="articleId")},
         *      inverseJoinColumns={@ORM'JoinColumn(name="subjectId", referencedColumnName="subjectId")}
         *      )
         */
        protected $subjects;
        /**
         *
         * @return 'Doctrine'Common'Collections'ArrayCollection 
         */
        public function getSubjects()
        {
            return $this->subjects;
        }        
        public function removeSubjects(){ $this->subjects = new 'Doctrine'Common'Collections'ArrayCollection(); return $this;  }