0

基本的に、私は2つのテーブル(記事とタグ)を持っており、いくつかの追加の属性と多対多(1つの記事に多くのタグを含めることができ、1つのタグを多くの記事に割り当てることができます)の関係を作りたいです。これをDoctrine2で書くには、2つの別々のリレーション(1対多、多対1)と、追加の属性を持つ1つのリレーションテーブルArticleTagに分割します。

私の問題は、Doctrine2を作成して結合テーブルエンティティも作成できるかどうかわからないことです。私が意味するのは、私が電話するときです:

$article = /* create new article, etc... */
$tag = /* create new tag, etc... */
$article->addTag($tag);

$em->persist($article);
$em->flush();

データベースにArticleエンティティとTagエンティティの両方を作成しますが、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;

}
4

2 に答える 2

2

これ自体を自動的に行う方法はありませんが、クラスのaddTagメソッドを次のように変更できます。Article

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の目から見たクラスはエンティティソースを表し、そのクラスの各インスタンスはエンティティを表します。単純な多対多のテーブルでは、多対多のテーブルはエンティティではありません。実際、これは2つのエンティティ間の関係にすぎません。そのため、Doctrineではこのロジックをバイパスでき、ArticleTag外部キーしかない場合はエンティティを必要としません。

ただし、そのテーブルにメタデータを追加すると、そのテーブルはリレーションシップテーブルではなくなります。私は物事を異なって見る多くの人々とこれについて話し合いました、しかしそれはただそうではありません。はい、エンティティ1とエンティティ2が関連していることを定義していますが、その追加の列は、関連付けに必要な追加のメタデータを定義しています。したがって、それ自体がエンティティであり、そのように反映する必要があります。

上に示したコードを追加するまで、私はかなり長い間これに苦労していました。

于 2013-01-09T18:18:05.420 に答える
0

私のエンティティは、参加エンティティなしでタグ(私のスキーマのサブジェクト)を使用して記事を参加できますが、特定の理由で参加エンティティが必要ですか?

利用方法

$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;  }
于 2013-01-09T17:08:03.357 に答える