Apa perbedaan antara inversedBy dan mappedBy?

102

Saya mengembangkan aplikasi saya menggunakan Zend Framework 2 dan Doctrine 2.

Saat menulis anotasi, saya tidak dapat memahami perbedaan antara mappedBydan inversedBy.

Kapan saya harus menggunakan mappedBy?

Kapan saya harus menggunakan inversedBy?

Kapan saya harus menggunakan keduanya?

Berikut ini contohnya:

 /**
 *
 * @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;

Saya melakukan pencarian cepat dan menemukan yang berikut, tetapi saya masih bingung:

Pengembang
sumber

Jawaban:

159
  • mappedBy harus ditentukan di sisi terbalik dari pengaitan (dua arah)
  • inversedBy harus ditentukan di sisi yang memiliki asosiasi (dua arah)

dari dokumentasi doktrin:

  • ManyToOne selalu memiliki sisi yang memiliki assocation dua arah.
  • OneToMany selalu merupakan sisi kebalikan dari asumsi dua arah.
  • Sisi yang memiliki asumsi OneToOne adalah entitas dengan tabel yang berisi kunci asing.

Lihat https://www.doctrine-project.org/projects/doctrine-orm/en/latest/reference/unitofwork-associations.html

Andreas Linden
sumber
1
Anehnya, pendokumentasi Doktrin memutuskan untuk meninggalkan contoh yaml dari banyak-ke-satu pemetaan dua arah, mungkin yang paling umum digunakan!
Peter Wooster
4
@PeterWooster, praktik terbaiknya adalah menggunakan Anotasi, karena Anda memiliki semua info tentang entitas di satu tempat!
Andreas Linden
Ini juga berlaku untuk banyak hubungan. Untuk itu: Anda dapat memilih sendiri sisi kepemilikan dari asosiasi banyak-ke-banyak.
11mb
5
@AndreasLinden banyak digunakan bukan berarti praktik terbaik. Sesuatu yang menggunakan komentar untuk menulis kode dengan cepat tidak pernah bisa dianggap sebagai praktik terbaik, ini bukan php asli, dan bahkan tidak disertakan secara default di semua kerangka kerja. Memiliki semua info tentang entitas di satu tempat adalah anti-argumen. Sejak mengelompokkan semua kode Anda ke satu tempat adalah hal yang baik? Sulit untuk menulis, sulit untuk mempertahankan, dan mengurangi organisasi dalam proyek Anda. praktek terbaik ? Duh.
JesusTheHun
4
@JesusTheHun Anda membandingkan apel dan pir. "semua kode" sangat berbeda dengan "semua info tentang suatu entitas";)
Andreas Linden
55

Jawaban di atas tidak cukup bagi saya untuk memahami apa yang sedang terjadi, jadi setelah mendalami lebih dalam saya rasa saya memiliki cara untuk menjelaskannya yang akan masuk akal bagi orang-orang yang berjuang seperti saya untuk mengerti.

inversedBy dan mappedBy digunakan oleh mesin DOKTRIN INTERNAL untuk mengurangi jumlah kueri SQL yang harus dilakukan untuk mendapatkan informasi yang Anda butuhkan. Untuk lebih jelasnya jika Anda tidak menambahkan inversedBy atau mappedBy, kode Anda akan tetap berfungsi tetapi tidak akan dioptimalkan .

Jadi misalnya, lihat kelas-kelas di bawah ini:

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;
}

Kelas-kelas ini jika Anda menjalankan perintah untuk menghasilkan skema (misalnya, bin/console doctrine:schema:update --force --dump-sql) Anda akan melihat bahwa tabel Kategori tidak memiliki kolom di atasnya untuk tugas. (ini karena tidak ada anotasi kolom di atasnya)

Hal penting yang harus dipahami di sini adalah bahwa tugas variabel hanya ada di sana sehingga mesin doktrin internal dapat menggunakan referensi di atasnya yang bertuliskan Kategori mappedBy. Sekarang ... jangan bingung di sini seperti saya dulu ... Kategori TIDAK mengacu pada NAMA KELAS , ini mengacu pada properti di kelas Tugas yang disebut 'dilindungi $ kategori'.

Seperti bijaksana, pada kelas Tasks properti $ category menyebutkan itu inversedBy = "tugas", perhatikan ini jamak, ini BUKAN JAMAK NAMA KELAS , tetapi hanya karena properti disebut 'dilindungi $ tugas' dalam Kategori kelas.

Setelah Anda memahami ini, menjadi sangat mudah untuk memahami apa yang dilakukan inversedBy dan mappedBy dan bagaimana menggunakannya dalam situasi ini.

Sisi yang mereferensikan kunci asing seperti 'tugas' dalam contoh saya selalu mendapatkan atribut inversedBy karena perlu mengetahui kelas apa (melalui perintah targetEntity) dan variabel apa (inversedBy =) pada kelas itu untuk 'bekerja mundur' sehingga berbicara dan mendapatkan informasi kategori dari. Cara mudah untuk mengingat ini, adalah kelas yang memiliki foreignkey_id adalah kelas yang harus memiliki inversedBy.

Sedangkan dengan kategori, dan properti $ tugasnya (yang tidak ada di tabel ingat, hanya sebagian dari kelas untuk tujuan pengoptimalan) adalah 'tugas' MappedBy, ini menciptakan hubungan resmi antara dua entitas sehingga doktrin sekarang dapat dengan aman gunakan pernyataan JOIN SQL, bukan dua pernyataan SELECT yang terpisah. Tanpa mappedBy, mesin doktrin tidak akan tahu dari pernyataan JOIN itu akan membuat variabel apa di kelas 'Tugas' untuk meletakkan informasi kategori.

Semoga ini menjelaskannya sedikit lebih baik.

Joseph Astrahan
sumber
6
Ini dijelaskan dengan sangat baik dan terima kasih atas usaha Anda. Saya datang dari Laravel Eloquent ke doktrin dan ini sulit bagi saya untuk memahami logikanya di sini. Sudah selesai dilakukan dengan baik. Category is NOT referring TO THE CLASS NAME, its referring to the property on the Task class called 'protected $category'semua yang saya butuhkan. Itu tidak hanya memecahkan masalah saya tetapi juga membantu saya untuk mengerti. Jawaban terbaik IMO :-)
The Alpha
1
Saya juga berasal dari Eloquent, ini sangat membantu saya. Satu-satunya poin penting saya sekarang adalah bagaimana mengatur setter / getter untuk ini, saya masih mempelajarinya
Eman
1
Ya itu sangat mudah dan bahkan otomatis dengan beberapa alat di luar sana, mulailah mengobrol dengan saya nanti dan saya dapat membantu Anda
Joseph Astrahan
1
Lihat jawaban ini, stackoverflow.com/questions/16629397/…
Joseph Astrahan
1
symfony.com/doc/current/doctrine/associations.html , ini lebih baik sebenarnya untuk dipelajari, symfony menggunakan doktrin sehingga akan mengajarkan Anda hal yang sama.
Joseph Astrahan
21

Dalam hubungan dua arah memiliki sisi memiliki dan sisi terbalik

mappedBy : dimasukkan ke Sisi kebalikan dari hubungan dua arah Untuk merujuk ke sisi pemiliknya

inversedBy : dimasukkan ke Sisi yang memiliki hubungan dua arah Untuk merujuk ke sisi kebalikannya

DAN

mappedBy digunakan dengan deklarasi pemetaan OneToOne, OneToMany, atau ManyToMany.

inversedBy atribut yang digunakan dengan deklarasi pemetaan OneToOne, ManyToOne, atau ManyToMany.

Perhatian : Sisi yang memiliki hubungan dua arah, sisi yang berisi kunci asing.

Ada dua referensi tentang inversedBy dan mappedBy ke Doctrine Documentation: First Link , Second Link

ahmed hamdy
sumber
1
Linknya sudah mati?
Scaramouche
2

5.9.1. Sisi Memiliki dan Terbalik

Untuk pengaitan Banyak-Ke-Banyak, Anda dapat memilih entitas mana yang merupakan pemilik dan sisi kebalikannya. Ada aturan semantik yang sangat sederhana untuk memutuskan sisi mana yang lebih cocok untuk menjadi sisi pemilik dari perspektif pengembang. Anda hanya perlu bertanya pada diri sendiri, entitas mana yang bertanggung jawab atas manajemen koneksi dan memilihnya sebagai pihak yang memiliki.

Ambil contoh dua entitas Article dan Tag. Kapan pun Anda ingin menghubungkan Artikel ke Tag dan sebaliknya, sebagian besar Artikel yang bertanggung jawab atas hubungan ini. Setiap kali Anda menambahkan artikel baru, Anda ingin menghubungkannya dengan tag yang ada atau yang baru. Formulir create Article Anda mungkin akan mendukung gagasan ini dan memungkinkan untuk menentukan tag secara langsung. Inilah mengapa Anda harus memilih Artikel sebagai sisi kepemilikan, karena ini membuat kode lebih mudah dipahami:

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

Micheal Mouner Mikhail Youssif
sumber