Dalam hal apa Anda menggunakan anotasi JPA @JoinTable?

Jawaban:

350

EDIT 2017-04-29 : Seperti yang ditunjukkan oleh beberapa komentator, JoinTablecontohnya tidak memerlukan mappedByatribut anotasi. Bahkan, versi terbaru dari Hibernate menolak untuk memulai dengan mencetak kesalahan berikut:

org.hibernate.AnnotationException: 
   Associations marked as mappedBy must not define database mappings 
   like @JoinTable or @JoinColumn

Mari kita berpura-pura bahwa Anda memiliki entitas bernama Projectdan entitas lain bernama Taskdan setiap proyek dapat memiliki banyak tugas.

Anda bisa mendesain skema database untuk skenario ini dengan dua cara.

Solusi pertama adalah membuat tabel bernama Projectdan tabel lain bernama Taskdan menambahkan kolom kunci asing ke tabel tugas bernama project_id:

Project      Task
-------      ----
id           id
name         name
             project_id

Dengan cara ini, akan mungkin untuk menentukan proyek untuk setiap baris di tabel tugas. Jika Anda menggunakan pendekatan ini, di kelas entitas Anda, Anda tidak perlu tabel bergabung:

@Entity
public class Project {

   @OneToMany(mappedBy = "project")
   private Collection<Task> tasks;

}

@Entity
public class Task {

   @ManyToOne
   private Project project;

}

Solusi lain adalah dengan menggunakan tabel ketiga, misalnya Project_Tasks, dan menyimpan hubungan antara proyek dan tugas dalam tabel itu:

Project      Task      Project_Tasks
-------      ----      -------------
id           id        project_id
name         name      task_id

The Project_Taskstabel disebut "Join Table". Untuk mengimplementasikan solusi kedua ini di JPA Anda perlu menggunakan@JoinTable anotasi. Misalnya, untuk menerapkan asosiasi satu-ke-satu yang uni-directional, kita dapat mendefinisikan entitas kita sebagai berikut:

Project kesatuan:

@Entity
public class Project {

    @Id
    @GeneratedValue
    private Long pid;

    private String name;

    @JoinTable
    @OneToMany
    private List<Task> tasks;

    public Long getPid() {
        return pid;
    }

    public void setPid(Long pid) {
        this.pid = pid;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<Task> getTasks() {
        return tasks;
    }

    public void setTasks(List<Task> tasks) {
        this.tasks = tasks;
    }
}

Task kesatuan:

@Entity
public class Task {

    @Id
    @GeneratedValue
    private Long tid;

    private String name;

    public Long getTid() {
        return tid;
    }

    public void setTid(Long tid) {
        this.tid = tid;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

Ini akan membuat struktur database berikut:

Diagram ER 1

The @JoinTablepenjelasan juga memungkinkan Anda menyesuaikan berbagai aspek tabel bergabung. Misalnya, sudahkah kami memberi anotasi pada tasksproperti seperti ini:

@JoinTable(
        name = "MY_JT",
        joinColumns = @JoinColumn(
                name = "PROJ_ID",
                referencedColumnName = "PID"
        ),
        inverseJoinColumns = @JoinColumn(
                name = "TASK_ID",
                referencedColumnName = "TID"
        )
)
@OneToMany
private List<Task> tasks;

Database yang dihasilkan akan menjadi:

Diagram ER 2

Akhirnya, jika Anda ingin membuat skema untuk asosiasi banyak-ke-banyak, menggunakan tabel bergabung adalah satu-satunya solusi yang tersedia.

Behrang Saeedzadeh
sumber
1
menggunakan pendekatan pertama saya memiliki Proyek saya diisi dengan tugas-tugas saya dan setiap Tugas diisi dengan Proyek induk sebelum penggabungan dan bekerja tetapi semua entri saya digandakan berdasarkan jumlah tugas saya. Proyek dengan dua tugas disimpan dua kali di basis data saya. Mengapa
MaikoID
UPDATE Tidak ada entri duplikat di database saya, hibernate memilih dengan bergabung luar kiri dan saya tidak tahu mengapa ..
MaikoID
2
Saya percaya @JoinTable/@JoinColumndapat dijelaskan pada bidang yang sama dengan mappedBy. Jadi contoh yang benar harus menjaga mappedBydi Project, dan memindahkan @JoinColumnke Task.project (atau sebaliknya)
Adrian Shum
2
Bagus! Tapi aku punya pertanyaan lebih lanjut: jika bergabung tabel Project_Tasksmembutuhkan namedari Taskjuga, yang menjadi tiga kolom: project_id, task_id, task_name, bagaimana untuk mencapai hal ini?
macemers
5
Saya pikir Anda seharusnya tidak memetakan Dengan menggunakan contoh kedua Anda untuk mencegah kesalahan iniCaused by: org.hibernate.AnnotationException: Associations marked as mappedBy must not define database mappings like @JoinTable or @JoinColumn:
karthik m
14

Juga lebih bersih untuk digunakan @JoinTableketika Entitas dapat menjadi anak dalam beberapa hubungan orang tua / anak dengan berbagai jenis orang tua. Untuk menindaklanjuti dengan contoh Behrang, bayangkan Tugas dapat menjadi anak dari Proyek, Orang, Departemen, Studi, dan Proses.

Haruskah tasktabel memiliki 5 nullablebidang kunci asing? Saya pikir tidak...

HDave
sumber
14

Ini satu-satunya solusi untuk memetakan asosiasi ManyToMany: Anda memerlukan tabel gabungan antara tabel dua entitas untuk memetakan asosiasi.

Ini juga digunakan untuk asosiasi OneToMany (biasanya searah) ketika Anda tidak ingin menambahkan kunci asing di tabel banyak sisi dan dengan demikian tetap independen dari satu sisi.

Cari @JoinTable di dokumentasi hibernate untuk penjelasan dan contoh.

JB Nizet
sumber
4

Ini memungkinkan Anda menangani hubungan Many to Many. Contoh:

Table 1: post

post has following columns
____________________
|  ID     |  DATE   |
|_________|_________|
|         |         |
|_________|_________|

Table 2: user

user has the following columns:

____________________
|     ID  |NAME     |
|_________|_________|
|         |         |
|_________|_________|

Bergabung dengan Tabel memungkinkan Anda membuat pemetaan menggunakan:

@JoinTable(
  name="USER_POST",
  joinColumns=@JoinColumn(name="USER_ID", referencedColumnName="ID"),
  inverseJoinColumns=@JoinColumn(name="POST_ID", referencedColumnName="ID"))

akan membuat tabel:

____________________
|  USER_ID| POST_ID |
|_________|_________|
|         |         |
|_________|_________|
slal
sumber
1
Pertanyaan: bagaimana jika saya sudah memiliki tabel tambahan ini? JoinTable tidak akan menimpa yang sudah ada, kan?
TheWandererr
@ TheWandererr apakah Anda menemukan jawaban untuk pertanyaan Anda? Saya sudah punya meja gabung
asgs
Dalam kasus saya itu membuat kolom berlebihan di tabel sisi memiliki. untuk mis. POST_ID dalam POST. Dapatkah Anda menyarankan mengapa ini terjadi?
SPS
0

@ManyToMany asosiasi

Paling sering, Anda harus menggunakan @JoinTableanotasi untuk menentukan pemetaan hubungan tabel banyak-ke-banyak:

  • nama tabel tautan dan
  • dua kolom Kunci Asing

Jadi, anggap Anda memiliki tabel database berikut:

Hubungan tabel banyak-ke-banyak

Di Postentitas, Anda akan memetakan hubungan ini, seperti ini:

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

The @JoinTablepenjelasan digunakan untuk menentukan nama tabel melaluiname atribut, serta kolom Foreign Key yang referensi yang posttabel (misalnya, joinColumns) dan kolom Foreign Key di post_tagtabel link yang referensi yang Tagentitas melalui inverseJoinColumnsatribut.

Perhatikan bahwa atribut kaskade @ManyToManyanotasi diatur ke PERSISTdanMERGE hanya karenaREMOVE adalah ide yang buruk karena kita pernyataan DELETE akan dikeluarkan untuk catatan induk lainnya, tagdalam kasus kami, bukan ke post_tagcatatan. Untuk detail lebih lanjut tentang topik ini, lihat artikel ini .

@OneToManyAsosiasi searah

@OneToManyAsosiasi searah , yang kurang a@JoinColumn pemetaan, berperilaku seperti hubungan tabel banyak-ke-banyak, bukan satu-ke-banyak.

Jadi, dengan asumsi Anda memiliki pemetaan entitas berikut:

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

    @Id
    @GeneratedValue
    private Long id;

    private String title;

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

    //Constructors, getters and setters removed for brevity
}

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

    @Id
    @GeneratedValue
    private Long id;

    private String review;

    //Constructors, getters and setters removed for brevity
}

Hibernate akan mengasumsikan skema database berikut untuk pemetaan entitas di atas:

Tabel kode asosiasi JPA satu arah <code> @OneToMany </code>

Seperti yang sudah dijelaskan, @OneToManypemetaan JPA searah berperilaku seperti asosiasi banyak-ke-banyak.

Untuk menyesuaikan tabel tautan, Anda juga dapat menggunakan @JoinTableanotasi:

@OneToMany(
    cascade = CascadeType.ALL,
    orphanRemoval = true
)
@JoinTable(
    name = "post_comment_ref",
    joinColumns = @JoinColumn(name = "post_id"),
    inverseJoinColumns = @JoinColumn(name = "post_comment_id")
)
private List<PostComment> comments = new ArrayList<>();

Dan sekarang, tabel tautan akan dipanggil post_comment_refdan kolom Kunci Asing akan post_id, untuk posttabel, dan post_comment_id, untukpost_comment tabel.

@OneToManyAsosiasi searah tidak efisien, jadi Anda lebih baik menggunakan @OneToManyasosiasi dua arah atau hanya @ManyToOnesisi. Lihat artikel ini untuk detail lebih lanjut tentang topik ini.

Vlad Mihalcea
sumber