inversedByとmappedByの違いは何ですか?


102

Zend Framework 2とDoctrine 2を使用してアプリケーションを開発しています。

注釈を足す間、私は違いを理解することができませんmappedByとしますinversedBy

いつ使用すべきmappedByですか?

いつ使用すべきinversedByですか?

どちらを使用すればよいですか?

次に例を示します。

 /**
 *
 * @ORM\OneToOne(targetEntity="\custMod\Entity\Person", mappedBy="customer")
 * @ORM\JoinColumn(name="personID", referencedColumnName="id")
 */
protected $person;

/**
 *
 * @ORM\OneToOne(targetEntity="\Auth\Entity\User")
 * @ORM\JoinColumn(name="userID", referencedColumnName="id")
 */
protected $user;

/**
 *
 * @ORM\ManyToOne (targetEntity="\custMod\Entity\Company", inversedBy="customer")
 * @ORM\JoinColumn (name="companyID", referencedColumnName="id")
 */
protected $company;

簡単な検索を行ったところ、次のことがわかりましたが、それでも混乱しています。

回答:


159
  • mappedByは、(双方向の)関連の逆側で指定する必要があります
  • (双方向)アソシエーションの所有側で、inversedByを指定する必要があります

教義のドキュメントから:

  • ManyToOneは常に双方向の関連付けの所有側です。
  • OneToManyは常に双方向の関連付けの逆側です。
  • OneToOne関連付けの所有側は、外部キーを含むテーブルを持つエンティティです。

https://www.doctrine-project.org/projects/doctrine-orm/en/latest/reference/unitofwork-associations.htmlを参照してください


1
奇妙なことに、Doctrineのドキュメント作成者は、おそらく最も一般的に使用されている多対1の双方向マッピングのyamlの例を省くことに決めました!
Peter Wooster

4
@PeterWoosterの場合、エンティティに関するすべての情報を1か所にまとめることができるため、ベストプラクティスはアノテーションを使用することです。
Andreas Linden

これは、多対多の関係にも当てはまります。それらの場合:多対多の関連付けの所有側を自分で選択できます。
2015

5
広く使用されている@AndreasLindenがベストプラクティスを意味するわけではありません。コメントを使用してオンザフライでコードを作成することはベストプラクティスとは見なされず、phpネイティブではなく、すべてのフレームワークにデフォルトで含まれていません。エンティティに関するすべての情報を1か所に持つことは、反論です。すべてのコードを1か所にまとめるのは良いことなので、それは、プロジェクトの組織を作成すること、維持すること、および組織を削減することの困難です。ベストプラクティス?ええと。
JesusTheHun

3
@JesusTheHunリンゴとナシを比較しています。「すべてのコード」は「エンティティに関するすべての情報」とは非常に異なります;)
Andreas Linden

55

上記の答えは私に何が起こっているのかを理解するのに十分ではなかったので、それをさらに掘り下げた後、私が理解したように苦労していた人々にとって理にかなっていると説明できる方法があると思います。

INTERNAL DOCTRINE エンジンは、inversedByおよびmappedByを使用して、必要な情報を取得するために必要なSQLクエリの数減らします。明確にするために、inversedByまたはmappedByを追加しない場合でも、コードは機能しますが最適化されません。

たとえば、以下のクラスを見てください。

class Task
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="task", type="string", length=255)
     */
    private $task;

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="dueDate", type="datetime")
     */
    private $dueDate;

    /**
     * @ORM\ManyToOne(targetEntity="Category", inversedBy="tasks", cascade={"persist"})
     * @ORM\JoinColumn(name="category_id", referencedColumnName="id")
     */
    protected $category;
}

class Category
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=255)
     */
    private $name;

    /**
     * @ORM\OneToMany(targetEntity="Task", mappedBy="category")
     */
    protected $tasks;
}

これらのクラスを使用してスキーマ(たとえば、bin/console doctrine:schema:update --force --dump-sql)を生成すると、Categoryテーブルには、タスク用の列がありません。(これには列の注釈がないためです)

ここで理解しておくべき重要なことは、可変タスクはそこにのみ存在するため、内部のドクトリンエンジンはその上の参照(mappedByカテゴリを示す)を使用できるということです。さて...私がそうだったように、ここで混乱しないでください... カテゴリはクラス名を参照していません。これは、「保護された$ category」と呼ばれるタスククラスのプロパティを参照しています。

同様に、Tasksクラスでは、プロパティ$ categoryはそれがinversedBy = "tasks"であると述べていますが、これは複数であることに注意してください。これはクラス名の数ではありませんが、プロパティがカテゴリで 'protected $ tasks'と呼ばれているためですクラス。

これを理解すると、inversedByとmappedByが何をしているか、そしてこの状況でそれらをどのように使用するかを理解するのが非常に簡単になります。

私の例で 'tasks'のような外部キーを参照している側は常に(inversedBy)属性を取得します。これは、(targetEntityコマンドを介して)クラスと、そのクラスのどの変数(inversedBy =)を知る必要があるためです。話し、カテゴリ情報を取得します。これを覚える簡単な方法は、foreignkey_idを持つクラスが、inversedByを持つ必要があるクラスです。

カテゴリの場合と同様に、その$ tasksプロパティ(テーブルにはありませんが、最適化の目的でクラスの一部のみです)がMappedBy 'tasks'である場合、これにより2つのエンティティ間に公式に関係が作成され、Doctrineが安全にできるようになります2つの個別のSELECTステートメントではなく、JOIN SQLステートメントを使用します。mapsByがない場合、DoctrineエンジンはJOINステートメントからは、クラス情報にどの変数を作成してカテゴリ情報を入れるかを認識しません。

これで少し良くなることを願っています。


6
これは非常によく説明され、あなたの努力に感謝します。私はLaravel Eloquentから教義に来ましたが、これはここでの論理を理解するのが困難でした。よくやった。Category is NOT referring TO THE CLASS NAME, its referring to the property on the Task class called 'protected $category'私が必要とするすべて。それは私の問題を解決しただけでなく、理解に役立ちました。ベストアンサーIMO :-)
アルファ

1
私もEloquentから来ました、これは私を大いに助けました。私の唯一のこだわりは、このためのセッター/ゲッターを設定する方法です。それでもロープを学んでいます
Eman

1
ええ、それは本当に簡単で、いくつかのツールで自動化されていても、後で私とチャットを開始して、あなたを助けることができます
Joseph Astrahan

1
この回答を確認してください。stackoverflow.com
questions / 16629397 /

1
symfony.com/doc/current/doctrine/associations.html、これは実際に学ぶ方が良いです、symfonyはdoctrineを使用するので同じことを教えます。
ジョセフアストラハン2017年

21

双方向の関係には、所有側と反対側の両方があります

mappedBy:双方向の関係の逆側に入れます。所有側を参照します。

reversedBy:双方向関係の所有側に入れます。その逆側を参照するには

そして

OneToOne、OneToMany、またはManyToManyマッピング宣言で使用されるmappedBy属性。

inversedByの OneToOne、ManyToOne、または多対多マッピング宣言で使用される属性。

通知:双方向関係の所有側、外部キーを含む側。

DoctrineドキュメンテーションへのinversedByとmapedByに関する2つの参照があります: 最初のリンク2番目のリンク


1
リンクが死んでいる?
Scaramouche

2

5.9.1。所有と逆側

多対多の関連付けでは、所有するエンティティと反対側のエンティティを選択できます。開発者の観点から、どちらの側が所有側に適しているかを決定する非常に単純なセマンティックルールがあります。どのエンティティが接続管理を担当しているかを自問するだけで、それを所有側として選択できます。

2つのエンティティArticleとTagの例を見てみましょう。ArticleをTagに、またはその逆に接続したいときはいつでも、この関係を担当しているのはほとんどArticleです。新しい記事を追加するときはいつでも、それを既存のタグまたは新しいタグに関連付ける必要があります。あなたの記事作成フォームはおそらくこの概念をサポートし、タグを直接指定することができます。コードをより理解しやすくするため、記事を所有側として選択するのはこのためです。

http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/association-mapping.html

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.