คุณใช้@JoinTable
บันทึกย่อJPA ในกรณีใด
คุณใช้@JoinTable
บันทึกย่อJPA ในกรณีใด
คำตอบ:
EDIT 2017-04-29 : ตามที่ผู้วิจารณ์บางคนชี้ให้เห็นJoinTable
ตัวอย่างไม่จำเป็นต้องมีmappedBy
แอตทริบิวต์คำอธิบายประกอบ อันที่จริงไฮเบอร์เนตรุ่นล่าสุดปฏิเสธที่จะเริ่มต้นด้วยการพิมพ์ข้อผิดพลาดต่อไปนี้:
org.hibernate.AnnotationException:
Associations marked as mappedBy must not define database mappings
like @JoinTable or @JoinColumn
สมมติว่าคุณมีชื่อเอนทิตีProject
และอีกชื่อเอนทิตีTask
และแต่ละโครงการสามารถมีงานได้มากมาย
คุณสามารถออกแบบคีมาฐานข้อมูลสำหรับสถานการณ์นี้ได้สองวิธี
วิธีแก้ปัญหาแรกคือการสร้างชื่อตารางProject
และอีกชื่อหนึ่งTask
และเพิ่มคอลัมน์กุญแจต่างประเทศในตารางงานที่ชื่อว่าproject_id
:
Project Task
------- ----
id id
name name
project_id
วิธีนี้จะเป็นไปได้ที่จะกำหนดโครงการสำหรับแต่ละแถวในตารางงาน ถ้าคุณใช้วิธีนี้ในคลาสเอนทิตี้ของคุณคุณไม่จำเป็นต้องเข้าร่วมตาราง:
@Entity
public class Project {
@OneToMany(mappedBy = "project")
private Collection<Task> tasks;
}
@Entity
public class Task {
@ManyToOne
private Project project;
}
โซลูชันอื่นคือใช้ตารางที่สามเช่นProject_Tasks
และเก็บความสัมพันธ์ระหว่างโครงการและงานในตารางนั้น:
Project Task Project_Tasks
------- ---- -------------
id id project_id
name name task_id
Project_Tasks
ตารางที่เรียกว่า "เข้าร่วมโต๊ะ" ในการใช้โซลูชันที่สองนี้ใน JPA คุณต้องใช้@JoinTable
คำอธิบายประกอบ ตัวอย่างเช่นในการดำเนินการเชื่อมโยงแบบหนึ่งต่อหลายกลุ่มเราสามารถกำหนดเอนทิตีของเราดังนี้:
Project
นิติบุคคล:
@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
นิติบุคคล:
@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;
}
}
สิ่งนี้จะสร้างโครงสร้างฐานข้อมูลต่อไปนี้:
@JoinTable
คำอธิบายประกอบยังช่วยให้คุณสามารถปรับแต่งด้านต่างๆของการเข้าร่วมโต๊ะ ตัวอย่างเช่นหากเราใส่คำอธิบายประกอบtasks
คุณสมบัติเช่นนี้:
@JoinTable(
name = "MY_JT",
joinColumns = @JoinColumn(
name = "PROJ_ID",
referencedColumnName = "PID"
),
inverseJoinColumns = @JoinColumn(
name = "TASK_ID",
referencedColumnName = "TID"
)
)
@OneToMany
private List<Task> tasks;
ฐานข้อมูลผลลัพธ์จะกลายเป็น:
ท้ายที่สุดถ้าคุณต้องการสร้างสคีมาสำหรับการเชื่อมโยงแบบกลุ่มต่อกลุ่มการใช้ตารางการเข้าร่วมเป็นโซลูชันที่มีให้เท่านั้น
@JoinTable/@JoinColumn
mappedBy
สามารถข้อเขียนบนสนามเดียวกันกับ ดังนั้นตัวอย่างที่ถูกต้องควรจะเก็บไว้mappedBy
ในProject
และย้าย@JoinColumn
ไปที่Task.project
(หรือในทางกลับกัน)
Project_Tasks
ความต้องการname
ของTask
เช่นกันซึ่งจะกลายเป็นสามคอลัมน์: project_id
, task_id
, task_name
วิธีการเพื่อให้บรรลุนี้?
Caused by: org.hibernate.AnnotationException: Associations marked as mappedBy must not define database mappings like @JoinTable or @JoinColumn:
นอกจากนี้ยังสะอาดกว่าการใช้ @JoinTable
เมื่อกิจการสามารถเป็นเด็กในความสัมพันธ์ของผู้ปกครอง / เด็กหลายคนกับผู้ปกครองประเภทต่างๆ ในการติดตามตัวอย่างของ Behrang ให้จินตนาการถึงภารกิจที่สามารถเป็นลูกของโครงการบุคคลแผนกการศึกษาและกระบวนการ
task
ตารางควรมี 5 nullable
เขตข้อมูลสำคัญต่างประเทศหรือไม่ ผมคิดว่าไม่...
มันเป็นทางออกเดียวที่จะจับคู่การเชื่อมโยง ManyToMany: คุณต้องเข้าร่วมตารางระหว่างตารางเอนทิตีสองแห่งเพื่อจับคู่การเชื่อมโยง
นอกจากนี้ยังใช้สำหรับการเชื่อมโยง OneToMany (โดยปกติเป็นทิศทางเดียว) เมื่อคุณไม่ต้องการเพิ่มคีย์ต่างประเทศในตารางของหลาย ๆ ด้านและทำให้เป็นอิสระจากด้านใดด้านหนึ่ง
ค้นหา @JoinTable ในเอกสาร hibernateสำหรับคำอธิบายและตัวอย่าง
มันช่วยให้คุณจัดการความสัมพันธ์แบบหลายต่อหลายคนได้ ตัวอย่าง:
Table 1: post
post has following columns
____________________
| ID | DATE |
|_________|_________|
| | |
|_________|_________|
Table 2: user
user has the following columns:
____________________
| ID |NAME |
|_________|_________|
| | |
|_________|_________|
ตารางเข้าร่วมให้คุณสร้างแผนที่โดยใช้:
@JoinTable(
name="USER_POST",
joinColumns=@JoinColumn(name="USER_ID", referencedColumnName="ID"),
inverseJoinColumns=@JoinColumn(name="POST_ID", referencedColumnName="ID"))
จะสร้างตาราง:
____________________
| USER_ID| POST_ID |
|_________|_________|
| | |
|_________|_________|
@ManyToMany
สมาคมบ่อยครั้งที่คุณจะต้องใช้@JoinTable
คำอธิบายประกอบเพื่อระบุการแมปความสัมพันธ์ของตารางแบบหลายต่อหลายกลุ่ม:
ดังนั้นสมมติว่าคุณมีตารางฐานข้อมูลต่อไปนี้:
ในPost
เอนทิตีคุณจะแมปความสัมพันธ์นี้เช่นนี้
@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<>();
@JoinTable
คำอธิบายประกอบถูกใช้เพื่อระบุชื่อตารางผ่านname
แอตทริบิวต์เช่นเดียวกับคอลัมน์ที่สำคัญต่างประเทศที่อ้างอิงpost
ตาราง (เช่นjoinColumns
) และคอลัมน์ที่สำคัญต่างประเทศในpost_tag
ตารางการเชื่อมโยงที่อ้างอิงTag
นิติบุคคลผ่านinverseJoinColumns
แอตทริบิวต์
โปรดสังเกตว่าแอตทริบิวต์ cascade ของ
@ManyToMany
คำอธิบายประกอบถูกตั้งค่าเป็นPERSIST
และMERGE
เนื่องจากการเรียงซ้อนREMOVE
เป็นแนวคิดที่ไม่ดีเนื่องจากเราจะมีการใช้คำสั่ง DELETE สำหรับเร็กคอร์ดพาเรนต์อื่นtag
ในกรณีของเราไม่ใช่post_tag
บันทึก สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับหัวข้อนี้ตรวจสอบบทความนี้
@OneToMany
เชื่อมโยงทิศทางเดียวการ@OneToMany
เชื่อมโยงทิศทางเดียวที่ขาด@JoinColumn
แมปจะทำงานเหมือนกับความสัมพันธ์ของตารางหลายต่อหลายกลุ่มมากกว่าหนึ่งต่อหลาย
ดังนั้นสมมติว่าคุณมีการแมปเอนทิตีต่อไปนี้:
@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
}
ไฮเบอร์เนตจะถือว่าสคีมาฐานข้อมูลต่อไปนี้สำหรับการจับคู่เอนทิตีด้านบน:
ดังที่ได้อธิบายไปแล้วการจับคู่@OneToMany
JPA แบบทิศทางเดียวมีลักษณะเหมือนการเชื่อมโยงแบบกลุ่มต่อกลุ่ม
หากต้องการกำหนดตารางลิงก์เองคุณสามารถใช้@JoinTable
คำอธิบายประกอบได้:
@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<>();
และตอนนี้ตารางการเชื่อมโยงเป็นไปได้เรียกว่าpost_comment_ref
และคอลัมน์ที่สำคัญต่างประเทศจะเป็นpost_id
สำหรับpost
ตารางและpost_comment_id
สำหรับpost_comment
ตาราง
การ
@OneToMany
เชื่อมโยงแบบทิศทางเดียวนั้นไม่มีประสิทธิภาพดังนั้นคุณควรใช้การ@OneToMany
เชื่อมโยงแบบสองทิศทางหรือ@ManyToOne
ด้านข้าง ลองอ่านบทความนี้สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับหัวข้อนี้