Perbedaan Antara Satu-ke-Banyak, Banyak-ke-Satu dan Banyak-ke-Banyak?

144

Ok jadi ini mungkin pertanyaan sepele tapi saya kesulitan memvisualisasikan dan memahami perbedaan dan kapan harus menggunakannya. Saya juga sedikit tidak jelas tentang bagaimana konsep seperti pemetaan uni-directional dan bi-directional mempengaruhi hubungan satu-ke-banyak / banyak-ke-banyak. Saya menggunakan Hibernate sekarang sehingga penjelasan apa pun yang terkait dengan ORM akan membantu.

Sebagai contoh, katakanlah saya memiliki pengaturan berikut:

public class Person{
    private Long personId;
    private Set<Skill> skills;
    //Getters and setters
}

public class Skill{
    private Long skillId;
    private String skillName;
    //Getters and setters
}

Jadi dalam hal ini pemetaan seperti apa yang akan saya miliki? Jawaban untuk contoh khusus ini sangat dihargai tetapi saya juga akan sangat menyukai gambaran kapan harus menggunakan satu-ke-banyak dan banyak-ke-banyak dan kapan menggunakan tabel gabungan versus kolom bergabung dan searah versus dua arah.

Ian Dallas
sumber
11
Sepertinya semua orang hanya menjawab Satu-ke-banyak vs Banyak-ke-banyak. Lihatlah jawaban saya untuk One-to-many vs Many-to-one.
Alexander Suraphel

Jawaban:

165

Satu-ke-Banyak : Satu Orang Memiliki Banyak Keahlian, Keterampilan tidak digunakan kembali di antara Orang

  • Searah : Seseorang dapat secara langsung merujuk Keterampilan melalui Perangkatnya
  • Bidirectional : Setiap Skill "child" memiliki satu pointer kembali ke Person (yang tidak ditampilkan dalam kode Anda)

Many-to-Many : Satu Orang Memiliki Banyak Keterampilan, Keterampilan digunakan kembali di antara Orang

  • Searah : Seseorang dapat secara langsung merujuk Keterampilan melalui Perangkatnya
  • Dua Arah : Keterampilan memiliki Set Orang yang berhubungan dengannya.

Dalam hubungan One-To-Many, satu objek adalah "orang tua" dan satu adalah "anak". Orang tua mengontrol keberadaan anak. Dalam Banyak-Untuk-Banyak, keberadaan kedua jenis tergantung pada sesuatu di luar keduanya (dalam konteks aplikasi yang lebih besar).

Subjek (domain) Anda harus menentukan apakah atau tidak hubungan itu Satu-Ke-Banyak atau Banyak-Banyak - namun, saya menemukan bahwa membuat hubungan searah atau dua arah adalah keputusan rekayasa yang memperdagangkan memori, pemrosesan, kinerja , dll.

Apa yang bisa membingungkan adalah bahwa hubungan Dua Arah Banyak ke Banyak tidak perlu simetris! Artinya, sekelompok Orang bisa menunjuk ke suatu keterampilan, tetapi keterampilan itu tidak perlu berhubungan kembali dengan orang-orang itu saja. Biasanya memang demikian, tetapi simetri semacam itu bukanlah keharusan. Ambil cinta, misalnya - itu dua arah ("I-Love", "Loves-Me"), tetapi sering asimetris ("Aku mencintainya, tapi dia tidak mencintaiku")!

Semua ini didukung dengan baik oleh Hibernate dan JPA. Hanya ingat bahwa Hibernate atau ORM lainnya tidak peduli tentang menjaga simetri ketika mengelola hubungan dua arah banyak-dua arah ... semuanya tergantung pada aplikasi.

HDave
sumber
Untuk memperjelas, hubungan apa pun mungkin satu atau dua arah dalam BL Anda atau dalam pemetaan O / R Anda (bahkan tidak tergantung satu sama lain, bahkan!).
jyoungdev
4
Contoh "CINTA" baru saja menjelaskannya. ManyToMany adalah tipe pemetaan saya.
Abdullah Khan
1
Super. Ini menjelaskannya dengan sangat baik (dan dalam konteks contoh OP)
Anupam
1
Tidak menjawab pertanyaan dengan benar. Anda melewatkan banyak bagian. walaupun satu ke banyak dan banyak ke satu adalah masalah persepsi jawaban ini tidak menyebutkan itu.
Manzur Alahi
248

Sepertinya semua orang menjawab One-to-manyvs Many-to-many.:

Perbedaan antara One-to-many, Many-to-onedan Many-to-Manyadalah:

One-to-manyvs Many-to-oneadalah masalah perspektif . Unidirectionalvs Bidirectionaltidak akan memengaruhi pemetaan tetapi akan membuat perbedaan tentang cara Anda dapat mengakses data Anda.

  • Dalam Many-to-onesatu manysisi akan menjaga referensi dari onesamping. Contoh yang baik adalah "Negara Bagian memiliki Kota". Dalam hal ini Stateadalah satu sisi dan Citybanyak sisi. Akan ada kolom state_iddi tabel cities.

Dalam searah , Personkelas akan List<Skill> skillstetapi Skilltidak akan memiliki Person person. Dalam dua arah , kedua properti ditambahkan dan memungkinkan Anda untuk mengakses Personketerampilan yang diberikan (yaitu skill.person).

  • Di One-to-Manysatu sisi akan menjadi titik acuan kami. Misalnya, "Pengguna memiliki Alamat". Dalam hal ini kita mungkin memiliki tiga kolom address_1_id, address_2_iddan address_3_idatau mencari tabel dengan batasan unik pada user_iddan address_id.

Dalam searah , Userakan ada Address address. Bidirectional akan memiliki tambahan List<User> usersdi Addresskelas.

  • Dalam Many-to-Manyanggota masing-masing pihak dapat memegang referensi ke jumlah anggota pihak lain yang sewenang-wenang. Untuk mencapai ini digunakan tabel pencarian . Contoh untuk ini adalah hubungan antara dokter dan pasien. Seorang dokter dapat memiliki banyak pasien dan sebaliknya.
Alexander Suraphel
sumber
27
ini harus menjadi jawaban yang diterima, sebagian besar jawaban lain ketinggalan pertanyaan.
arg20
Contoh pertama salah. Jika Anda memiliki Seseorang dan Seseorang memiliki @OneToMany dengan Keterampilan, tabel preson_skills itu akan memiliki batasan unik pada skill_id. Jadi satu keterampilan akan dipetakan hanya untuk satu orang. Dan Anda tidak dapat mengekstraksi s.persons, karena hanya adas.person
Иван Николайчук
Sebenarnya One-to-manyhubungan seperti yang Anda gambarkan adalah Many-to-manyhubungan karena personmemiliki referensi ke banyak skillstetapi skilltidak menyimpan referensi ke orang tertentu dan banyak yang personsdapat memiliki referensi yang sama skill. Dan Many-to-onehubungan Anda sebenarnya One-to-manykarena setiap keterampilan hanya merujuk ke satu personkarena seorang anak hanya memiliki satu ibu.
mixel
@mixel komentar Anda akhirnya membuat saya menulis ulang sebagian besar jawaban saya. Silakan periksa lagi! Terima kasih
Alexander Suraphel
Anda membedakan antara Satu-ke-banyak dan Banyak-ke-satu dengan signifikansi sisi "Satu". Dalam kedua contoh "Pengguna" adalah entitas yang paling signifikan. Jadi ketika itu ada di "Satu" (pengguna dan keterampilan, skillsmiliki person_id) maka Anda menyebutnya Satu-ke-banyak tetapi ketika itu satu sisi "Banyak" (pengguna dan alamat, usersmiliki address_id) maka Anda menyebutnya Banyak-ke-satu. Tetapi secara struktural kedua kasus itu identik dan disebut Satu-ke-banyak.
mixel
38

1) Lingkaran adalah Entitas / POJO / Kacang

2) deg adalah singkatan untuk derajat seperti pada grafik (jumlah sisi)

PK = Kunci primer, FK = Kunci asing

Perhatikan kontradiksi antara derajat dan nama sisi. Banyak berkorespondensi dengan derajat = 1 sementara Satu berkorespondensi dengan derajat> 1.

Ilustrasi satu-ke-banyak banyak-ke-satu

jhegedus
sumber
1
Sangat suka bagaimana ini mengikat grafik objek ke tabel di kedua arah.
Dmitry Minkovsky
3
Kutu buku lihat, ini adalah bagaimana PROGRAMMER ini TULISAN TANGAN terlihat seperti: D
Mehraj Malik
Saya melihat apa yang Anda lakukan di sini.
Nick Gallimore
8

Lihatlah artikel ini: Memetakan Hubungan Objek

Ada dua kategori hubungan objek yang perlu Anda perhatikan saat memetakan. Kategori pertama didasarkan pada multiplisitas dan mencakup tiga jenis:

*One-to-one relationships.  This is a relationship where the maximums of each of its multiplicities is one, an example of which is holds relationship between Employee and Position in Figure 11.  An employee holds one and only one position and a position may be held by one employee (some positions go unfilled).
*One-to-many relationships. Also known as a many-to-one relationship, this occurs when the maximum of one multiplicity is one and the other is greater than one.  An example is the works in relationship between Employee and Division.  An employee works in one division and any given division has one or more employees working in it.
*Many-to-many relationships. This is a relationship where the maximum of both multiplicities is greater than one, an example of which is the assigned relationship between Employee and Task.  An employee is assigned one or more tasks and each task is assigned to zero or more employees. 

Kategori kedua didasarkan pada directionality dan berisi dua jenis, hubungan uni-directional dan hubungan dua arah.

*Uni-directional relationships.  A uni-directional relationship when an object knows about the object(s) it is related to but the other object(s) do not know of the original object.  An example of which is the holds relationship between Employee and Position in Figure 11, indicated by the line with an open arrowhead on it.  Employee objects know about the position that they hold, but Position objects do not know which employee holds it (there was no requirement to do so).  As you will soon see, uni-directional relationships are easier to implement than bi-directional relationships.
*Bi-directional relationships.  A bi-directional relationship exists when the objects on both end of the relationship know of each other, an example of which is the works in relationship between Employee and Division.  Employee objects know what division they work in and Division objects know what employees work in them. 
alejandrobog
sumber
2
this occurs when the maximum of one multiplicity is one and the other is greater than onelolwut?
serg
3

Ini adalah pertanyaan yang sangat umum, jadi jawaban ini didasarkan pada artikel yang saya tulis di blog saya.

Satu-ke-banyak

Hubungan tabel satu-ke-banyak terlihat sebagai berikut:

Satu-ke-banyak

Dalam sistem database relasional, hubungan tabel satu-ke-banyak menghubungkan dua tabel berdasarkan Foreign Keykolom pada anak yang merujuk pada Primary Keybaris tabel induk.

Dalam diagram tabel di atas, post_idkolom dalam post_commenttabel memiliki Foreign Keyhubungan dengan kolom postid tabel Primary Key:

ALTER TABLE
    post_comment
ADD CONSTRAINT
    fk_post_comment_post_id
FOREIGN KEY (post_id) REFERENCES post

@ManyToOne penjelasan

Cara terbaik untuk memetakan hubungan tabel satu-ke-banyak adalah dengan menggunakan @ManyToOneanotasi.

Dalam kasus kami, entitas anak, PostCommentmemetakan post_idkolom Kunci Asing menggunakan @ManyToOneanotasi:

@Entity(name = "PostComment")
@Table(name = "post_comment")
public class PostComment {

    @Id
    @GeneratedValue
    private Long id;

    private String review;

    @ManyToOne(fetch = FetchType.LAZY)
    private Post post;

}

Menggunakan @OneToManyanotasi JPA

Hanya karena Anda memiliki opsi untuk menggunakan @OneToManyanotasi, itu tidak berarti ini harus menjadi opsi default untuk setiap hubungan database satu-ke-banyak . Masalah dengan koleksi adalah bahwa kita hanya bisa menggunakannya ketika jumlah catatan anak agak terbatas.

Cara terbaik untuk memetakan @OneToManyasosiasi adalah dengan mengandalkan @ManyToOnesisi untuk menyebarkan semua perubahan status entitas:

@Entity(name = "Post")
@Table(name = "post")
public class Post {

    @Id
    @GeneratedValue
    private Long id;

    private String title;

    @OneToMany(
        mappedBy = "post", 
        cascade = CascadeType.ALL, 
        orphanRemoval = true
    )
    private List<PostComment> comments = new ArrayList<>();

    //Constructors, getters and setters removed for brevity

    public void addComment(PostComment comment) {
        comments.add(comment);
        comment.setPost(this);
    }

    public void removeComment(PostComment comment) {
        comments.remove(comment);
        comment.setPost(null);
    }
}

Entitas induk Post,, menampilkan dua metode utilitas (misalnya addCommentdan removeComment) yang digunakan untuk menyinkronkan kedua sisi dari asosiasi dua arah. Anda harus selalu memberikan metode ini setiap kali Anda bekerja dengan asosiasi dua arah karena, jika tidak, Anda berisiko mengalami masalah propagasi negara yang sangat halus .

@OneToManyAsosiasi searah harus dihindari karena kurang efisien daripada menggunakan @ManyToOneatau @OneToManyasosiasi dua arah .

Untuk detail lebih lanjut tentang cara terbaik untuk memetakan @OneToManyhubungan dengan JPA dan Hibernate, lihat artikel ini .

Satu-ke-satu

Hubungan tabel satu-ke-satu terlihat sebagai berikut:

Satu-ke-satu

Dalam sistem basis data relasional, hubungan tabel satu-ke-satu menghubungkan dua tabel berdasarkan Primary Keykolom pada anak yang juga merupakan Foreign Keyreferensi Primary Keydari baris tabel induk.

Oleh karena itu, kita dapat mengatakan bahwa tabel anak berbagi Primary Keydengan tabel induk.

Dalam diagram tabel di atas, idkolom dalam post_detailstabel juga memiliki Foreign Keyhubungan dengan kolom posttabel id Primary Key:

ALTER TABLE
    post_details
ADD CONSTRAINT
    fk_post_details_id
FOREIGN KEY (id) REFERENCES post

Menggunakan JPA @OneToOnedengan @MapsIdanotasi

Cara terbaik untuk memetakan @OneToOnehubungan adalah menggunakan @MapsId. Dengan cara ini, Anda bahkan tidak memerlukan asosiasi dua arah karena Anda selalu dapat mengambil PostDetailsentitas dengan menggunakan Postpengidentifikasi entitas.

Pemetaannya terlihat seperti ini:

[kode bahasa = "java"] @Entity (name = "PostDetails") @Table (name = "post_details") kelas publik PostDetails {

@Id
private Long id;

@Column(name = "created_on")
private Date createdOn;

@Column(name = "created_by")
private String createdBy;

@OneToOne(fetch = FetchType.LAZY)
@MapsId
@JoinColumn(name = "id")
private Post post;

public PostDetails() {}

public PostDetails(String createdBy) {
    createdOn = new Date();
    this.createdBy = createdBy;
}

//Getters and setters omitted for brevity

} [/ kode]

Dengan cara ini, idproperti berfungsi sebagai Primary Key dan Foreign Key. Anda akan melihat bahwa @Idkolom tidak lagi menggunakan @GeneratedValueanotasi karena pengenal diisi dengan pengidentifikasi postasosiasi.

Untuk detail lebih lanjut tentang cara terbaik untuk memetakan @OneToOnehubungan dengan JPA dan Hibernate, lihat artikel ini .

Banyak ke banyak

Hubungan tabel banyak-ke-banyak terlihat sebagai berikut:

Banyak ke banyak

Dalam sistem basis data relasional, hubungan banyak-ke-banyak tabel menghubungkan dua tabel induk melalui tabel anak yang berisi dua Foreign Keykolom referensi Primary Keykolom dari dua tabel induk.

Dalam diagram tabel di atas, post_idkolom dalam post_tagtabel juga memiliki Foreign Keyhubungan dengan kolom postid tabel Primary Key:

ALTER TABLE
    post_tag
ADD CONSTRAINT
    fk_post_tag_post_id
FOREIGN KEY (post_id) REFERENCES post

Dan, tag_idkolom dalam post_tagtabel memiliki Foreign Keyhubungan dengan kolom tagid tabel Primary Key:

ALTER TABLE
    post_tag
ADD CONSTRAINT
    fk_post_tag_tag_id
FOREIGN KEY (tag_id) REFERENCES tag

Menggunakan @ManyToManypemetaan JPA

Ini adalah bagaimana Anda bisa memetakan many-to-manyhubungan tabel dengan JPA dan Hibernate:

@Entity(name = "Post")
@Table(name = "post")
public class Post {

    @Id
    @GeneratedValue
    private Long id;

    private String title;

    @ManyToMany(cascade = { 
        CascadeType.PERSIST, 
        CascadeType.MERGE
    })
    @JoinTable(name = "post_tag",
        joinColumns = @JoinColumn(name = "post_id"),
        inverseJoinColumns = @JoinColumn(name = "tag_id")
    )
    private Set<Tag> tags = new HashSet<>();

    //Getters and setters ommitted for brevity

    public void addTag(Tag tag) {
        tags.add(tag);
        tag.getPosts().add(this);
    }

    public void removeTag(Tag tag) {
        tags.remove(tag);
        tag.getPosts().remove(this);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Post)) return false;
        return id != null && id.equals(((Post) o).getId());
    }

    @Override
    public int hashCode() {
        return 31;
    }
}

@Entity(name = "Tag")
@Table(name = "tag")
public class Tag {

    @Id
    @GeneratedValue
    private Long id;

    @NaturalId
    private String name;

    @ManyToMany(mappedBy = "tags")
    private Set<Post> posts = new HashSet<>();

    //Getters and setters ommitted for brevity

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Tag tag = (Tag) o;
        return Objects.equals(name, tag.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name);
    }
}
  1. The tagsasosiasi dalam Postentitas hanya mendefinisikan PERSISTdan MERGEkaskade jenis. Seperti dijelaskan dalam artikel ini , REMOVE transisi status entitas tidak masuk akal untuk @ManyToManyasosiasi JPA karena hal itu dapat memicu penghapusan berantai yang pada akhirnya akan menghapus kedua sisi asosiasi.
  2. Sebagaimana dijelaskan dalam artikel ini , metode tambah / hapus utilitas wajib jika Anda menggunakan asosiasi dua arah sehingga Anda dapat memastikan bahwa kedua sisi asosiasi tersebut sinkron.
  3. The Postentitas menggunakan entitas pengidentifikasi untuk kesetaraan karena tidak memiliki tombol apa saja bisnis yang unik. Seperti yang dijelaskan dalam artikel ini , Anda dapat menggunakan pengidentifikasi entitas untuk kesetaraan selama Anda memastikan bahwa itu tetap konsisten di semua transisi status entitas .
  4. The Tagentitas memiliki kunci bisnis yang unik yang ditandai dengan Hibernate spesifik @NaturalIdpenjelasan. Ketika itu masalahnya, kunci bisnis yang unik adalah kandidat terbaik untuk pemeriksaan kesetaraan .
  5. The mappedByatribut dari postsasosiasi dalam Tagtanda entitas yang, dalam hubungan dua arah ini, Postentitas memiliki asosiasi. Ini diperlukan karena hanya satu sisi yang dapat memiliki hubungan, dan perubahan hanya disebarkan ke database dari sisi tertentu ini.
  6. Ini Setlebih disukai, karena menggunakan Listdengan @ManyToManykurang efisien.

Untuk detail lebih lanjut tentang cara terbaik untuk memetakan @ManyToManyhubungan dengan JPA dan Hibernate, lihat artikel ini .

Vlad Mihalcea
sumber
1

ini mungkin akan memanggil kapal banyak-ke-banyak hubungan sebagai berikut



public class Person{

    private Long personId;
    @manytomany

    private Set skills;
    //Getters and setters
}

public class Skill{
    private Long skillId;
    private String skillName;
    @manyToMany(MappedBy="skills,targetClass="Person")
    private Set persons; // (people would not be a good convenion)
    //Getters and setters
}

Anda mungkin perlu mendefinisikan joinTable + JoinColumn tetapi mungkin juga berfungsi tanpa ...

msshapira
sumber
1

Saya akan menjelaskan seperti itu:

OneToOne - hubungan OneToOne

@OneToOne
Person person;

@OneToOne
Nose nose;

OneToMany - Hubungan ManyToOne

@OneToMany
Shepherd> shepherd;

@ManyToOne
List<Sheep> sheeps;

Hubungan ManyToMany - ManyToMany

@ManyToMany
List<Traveler> travelers;

@ManyToMany
List<Destination> destinations;
Duracell De Monaco
sumber
0

Pertama-tama, baca semua cetak halus. Perhatikan bahwa pemetaan relasional NHibernate (dengan demikian, saya asumsikan juga Hibernate) memiliki korespondensi lucu dengan DB dan pemetaan objek grafik. Misalnya, hubungan satu-ke-satu sering diimplementasikan sebagai hubungan banyak-ke-satu.

Kedua, sebelum kami dapat memberi tahu Anda bagaimana Anda harus menulis peta O / R Anda, kami juga harus melihat DB Anda. Secara khusus, dapatkah Keterampilan tunggal dimiliki oleh banyak orang? Jika demikian, Anda memiliki hubungan banyak-ke-banyak; jika tidak, ini banyak-ke-satu.

Ketiga, saya lebih suka untuk tidak menerapkan hubungan banyak-ke-banyak secara langsung, tetapi sebagai gantinya memodelkan "tabel gabungan" dalam model domain Anda - yaitu, memperlakukannya sebagai entitas, seperti ini:

class PersonSkill 
{
    Person person;
    Skill skill;    
}

Lalu apakah Anda melihat apa yang Anda miliki? Anda memiliki dua hubungan satu-ke-banyak. (Dalam hal ini, Orang mungkin memiliki koleksi PersonSkills, tetapi tidak akan memiliki kumpulan Keterampilan.) Namun, beberapa akan lebih suka menggunakan hubungan banyak-ke-banyak (antara Person dan Keterampilan); ini kontroversial.

Keempat, jika Anda memiliki hubungan dua arah (misalnya, tidak hanya Orang memiliki koleksi Keterampilan, tetapi juga, Keterampilan memiliki koleksi Orang), NHibernate tidak memberlakukan bidirectionality di BL Anda untuk Anda; hanya memahami dua arah hubungan untuk tujuan kegigihan.

Kelima, banyak-ke-satu jauh lebih mudah digunakan dengan benar di NHibernate (dan saya berasumsi Hibernate) daripada satu-ke-banyak (pemetaan koleksi).

Semoga berhasil!

jyoungdev
sumber