อะไรคือความแตกต่างระหว่าง inversedBy และ mappedBy?


102

ฉันกำลังพัฒนาแอปพลิเคชันของฉันโดยใช้ Zend Framework 2 และ Doctrine 2

ในขณะที่การเขียนคำอธิบายประกอบผมไม่สามารถที่จะเข้าใจความแตกต่างระหว่างและmappedByinversedBy

ฉันควรใช้เมื่อใด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-association.html


1
แปลกที่ผู้จัดทำเอกสารหลักคำสอนตัดสินใจที่จะละทิ้งตัวอย่างการทำแผนที่สองทิศทางแบบหลายต่อหนึ่งซึ่งอาจเป็นวิธีที่ใช้กันมากที่สุด!
Peter Wooster

4
@PeterWooster แนวทางปฏิบัติที่ดีที่สุดคือการใช้คำอธิบายประกอบเนื่องจากคุณมีข้อมูลทั้งหมดเกี่ยวกับเอนทิตีในที่เดียว!
Andreas Linden

สิ่งนี้ยังหมายถึงความสัมพันธ์หลาย ๆ ด้าน สำหรับสิ่งเหล่านี้: คุณสามารถเลือกฝั่งที่เป็นเจ้าของการเชื่อมโยงแบบกลุ่มต่อกลุ่มได้ด้วยตัวคุณเอง
11mb

5
@AndreasLinden ใช้กันอย่างแพร่หลายไม่ได้หมายถึงแนวทางปฏิบัติที่ดีที่สุด บางสิ่งที่ใช้ความคิดเห็นในการเขียนโค้ดได้ทันทีไม่สามารถถือเป็นแนวทางปฏิบัติที่ดีที่สุดได้ไม่ใช่ php เนทีฟและยังไม่รวมอยู่ในกรอบงานทั้งหมดโดยค่าเริ่มต้น การมีข้อมูลทั้งหมดเกี่ยวกับเอนทิตีในที่เดียวเป็นการต่อต้านการโต้แย้ง เนื่องจากเมื่อจัดกลุ่มรหัสทั้งหมดของคุณไว้ในที่เดียวเป็นสิ่งที่ดี? มันเป็นความเจ็บปวดในการเขียนความเจ็บปวดในการรักษาและลดองค์กรในโครงการของคุณ ปฏิบัติที่ดีที่สุด ? Duh.
JesusTheHun

4
@JesusTheHun คุณกำลังเปรียบเทียบแอปเปิ้ลและลูกแพร์ "รหัสทั้งหมด" แตกต่างกันมากกับ "ข้อมูลทั้งหมดเกี่ยวกับเอนทิตี";)
Andreas Linden

55

คำตอบข้างต้นไม่เพียงพอสำหรับฉันที่จะเข้าใจสิ่งที่เกิดขึ้นดังนั้นหลังจากเจาะลึกมากขึ้นฉันคิดว่าฉันมีวิธีอธิบายที่จะสมเหตุสมผลสำหรับคนที่ดิ้นรนอย่างฉันจะเข้าใจ

inversedBy และ mappedBy ถูกใช้โดยเอ็นจิ้น INTERNAL DOCTRINEเพื่อลดจำนวนคิวรี 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) คุณจะสังเกตเห็นว่าตารางหมวดหมู่ไม่มีคอลัมน์สำหรับงาน (เนื่องจากไม่มีคำอธิบายประกอบคอลัมน์)

สิ่งสำคัญที่ต้องทำความเข้าใจที่นี่คืองานตัวแปรมีเพียงที่นั่นเพื่อให้เครื่องมือหลักคำสอนภายในสามารถใช้การอ้างอิงด้านบนซึ่งระบุว่า mappedBy Category ตอนนี้ ... อย่าสับสนที่นี่เหมือนที่ฉันเป็น ... หมวดหมู่ไม่ได้หมายถึง CLASS NAMEซึ่งหมายถึงคุณสมบัติในคลาสงานที่เรียกว่า 'ประเภท $ ที่ได้รับการป้องกัน'

เช่นเดียวกับที่ชาญฉลาดในคลาส Tasks คุณสมบัติที่ $ ระบุว่าเป็น inversedBy = "งาน" สังเกตว่านี่เป็นพหูพจน์นี่ไม่ใช่ PLURAL ของ CLASS NAMEแต่เป็นเพราะคุณสมบัติถูกเรียกว่า 'protected $ งาน' ในหมวดหมู่ ชั้นเรียน.

เมื่อคุณเข้าใจสิ่งนี้แล้วมันจะง่ายมากที่จะเข้าใจว่า inversedBy และ mappedBy กำลังทำอะไรอยู่และจะใช้มันอย่างไรในสถานการณ์นี้

ด้านที่อ้างถึงคีย์ต่างประเทศเช่น 'งาน' ในตัวอย่างของฉันมักจะได้รับแอตทริบิวต์ inversedBy เนื่องจากต้องการทราบว่าคลาสใด (ผ่านคำสั่ง targetEntity) และตัวแปรใด (inversedBy =) ในคลาสนั้นเพื่อ 'ทำงานย้อนกลับ' เพื่อ พูดและรับข้อมูลหมวดหมู่จาก วิธีง่ายๆในการจำสิ่งนี้คือคลาสที่จะมี Foreignkey_id คือคลาสที่ต้องมี inversedBy

ในกรณีที่เป็นหมวดหมู่และคุณสมบัติ $ งาน (ซึ่งไม่ได้อยู่ในตารางโปรดจำไว้ว่าเพียงส่วนหนึ่งของคลาสเพื่อวัตถุประสงค์ในการเพิ่มประสิทธิภาพ) คือ MappedBy 'งาน' สิ่งนี้จะสร้างความสัมพันธ์อย่างเป็นทางการระหว่างทั้งสองเอนทิตีเพื่อให้หลักคำสอนสามารถทำได้อย่างปลอดภัย ใช้คำสั่ง JOIN SQL แทนสองคำสั่ง SELECT แยกกัน หากไม่มีการแมปโดยเครื่องมือหลักคำสอนจะไม่ทราบจากคำสั่ง 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 :-)
The Alpha

1
ฉันมาจาก Eloquent เช่นกันสิ่งนี้ช่วยฉันได้มาก จุดยึดเดียวของฉันตอนนี้คือวิธีการตั้งค่า setter / getter สำหรับสิ่งนี้ฉันยังคงเรียนรู้เชือกอยู่
Eman

1
ใช่มันง่ายมากและยังทำงานอัตโนมัติด้วยเครื่องมือบางอย่างที่นั่นเริ่มแชทกับฉันในภายหลังและฉันสามารถช่วยคุณได้
Joseph Astrahan

1
ลองดูคำตอบนี้stackoverflow.com/questions/16629397/…
Joseph Astrahan

1
symfony.com/doc/current/doctrine/association.htmlสิ่งนี้ดีกว่าที่จะเรียนรู้ symfony ใช้หลักคำสอนดังนั้นมันจะสอนคุณในสิ่งเดียวกัน
Joseph Astrahan

21

ในความสัมพันธ์แบบสองทิศทางมีทั้งด้านที่เป็นเจ้าของและด้านผกผัน

mappedBy : ใส่ลงในด้านผกผันของความสัมพันธ์แบบสองทิศทางเพื่ออ้างถึงฝั่งที่เป็นเจ้าของ

inversedBy : ใส่ลงในด้านการเป็นเจ้าของของความสัมพันธ์แบบสองทิศทางเพื่ออ้างถึงด้านผกผัน

และ

mappedByแอตทริบิวต์ที่ใช้กับการประกาศการแมป OneToOne, OneToMany หรือ ManyToMany

แอตทริบิวต์inversedBy ที่ใช้กับการประกาศการแมป OneToOne, ManyToOne หรือ ManyToMany

ข้อสังเกต : ด้านที่เป็นเจ้าของของความสัมพันธ์แบบสองทิศทางคือด้านที่มีคีย์ต่างประเทศ

มีการอ้างอิงสองครั้งเกี่ยวกับ inversedBy และ mappedBy ในเอกสารหลักคำสอน: First Link , Second Link


1
ลิงค์ตาย?
Scaramouche

2

5.9.1. การเป็นเจ้าของและผกผัน

สำหรับการเชื่อมโยงแบบกลุ่มต่อกลุ่มคุณสามารถเลือกเอนทิตีที่เป็นเจ้าของและฝ่ายผกผัน มีกฎความหมายที่ง่ายมากในการตัดสินใจว่าฝ่ายใดเหมาะสมที่จะเป็นเจ้าของจากมุมมองของนักพัฒนา คุณต้องถามตัวเองเท่านั้นว่าหน่วยงานใดรับผิดชอบการจัดการการเชื่อมต่อและเลือกสิ่งนั้นเป็นฝ่ายเป็นเจ้าของ

ยกตัวอย่างของสองเอนทิตี Article และ Tag เมื่อใดก็ตามที่คุณต้องการเชื่อมต่อบทความกับแท็กและในทางกลับกันส่วนใหญ่เป็นบทความที่รับผิดชอบความสัมพันธ์นี้ เมื่อใดก็ตามที่คุณเพิ่มบทความใหม่คุณต้องการเชื่อมต่อกับแท็กที่มีอยู่หรือแท็กใหม่ แบบฟอร์มการสร้างบทความของคุณอาจสนับสนุนแนวคิดนี้และอนุญาตให้ระบุแท็กโดยตรง นี่คือเหตุผลที่คุณควรเลือกบทความเป็นฝั่งเจ้าของเนื่องจากทำให้เข้าใจรหัสได้มากขึ้น:

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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.