6.1 การจัดการการพึ่งพาอย่างลึกซึ้ง

และสิ่งที่เป็นประโยชน์และน่าสนใจเพิ่มเติมเกี่ยวกับ คำอธิบายประกอบ @OneToManyและอื่นๆ พวกเขาทั้งหมดมี 4 ตัวเลือกที่ใช้กันทั่วไป:

  • น้ำตก = CascadeType.ALL
  • orphanRemoval = จริง
  • ดึงข้อมูล = FetchType.LAZY

ตอนนี้เราจะวิเคราะห์รายละเอียดเพิ่มเติม และเราจะเริ่มต้นด้วยสิ่งที่น่าสนใจที่สุด - CascadeType . พารามิเตอร์นี้กำหนดว่าจะเกิดอะไรขึ้นกับเอนทิตีที่ขึ้นต่อกันหากเราเปลี่ยนเอนทิตีหลัก

ข้อกำหนด JPA มีค่าต่อไปนี้สำหรับพารามิเตอร์นี้:

  • ทั้งหมด
  • ยังคงมีอยู่
  • ผสาน
  • ลบ
  • รีเฟรช
  • ถอด

อย่างไรก็ตาม Hibernate ได้ขยายข้อกำหนดนี้ออกเป็นสามตัวเลือกเพิ่มเติม:

  • ทำซ้ำ
  • บันทึก_อัปเดต
  • ล็อค

แน่นอนว่ามีความคล้ายคลึงกันอย่างมากกับฐานข้อมูลและ CONSTRANIS อย่างไรก็ตามยังมีความแตกต่าง ไฮเบอร์เนตพยายามซ่อนการทำงานจริงกับฐานข้อมูลให้ได้มากที่สุด ดังนั้น Hibernate Cascades เหล่านี้จึงเกี่ยวกับวัตถุเอนทิตีทุกประการ

6.2 ประเภทคาสเคด

พารามิเตอร์ cascade อธิบายถึงสิ่งที่จะเกิดขึ้นกับออบเจกต์ที่ขึ้นต่อกันหากเราเปลี่ยนพาเรนต์ (ออบเจ็กต์หลัก) บ่อยที่สุด พารามิเตอร์นี้ใช้ร่วมกับคำอธิบายประกอบที่อธิบายการขึ้นต่อกันของวัตถุ:

ตัวอย่าง:

OneToOne(cascade = CascadeType.ALL)

หรือแบบนี้:

@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})

นอกจากนี้ยังสามารถเขียนเป็นคำอธิบายประกอบแยกต่างหาก:

@Cascade({ org.hibernate.annotations.CascadeType.ALL })

ตอนนี้เรามาพูดเพิ่มเติมเกี่ยวกับความหมายของคำอธิบายประกอบเหล่านี้

6.3 ทั้งหมด คงอยู่ รวม

CascadeType.ALLหมายความว่าการดำเนินการทั้งหมดที่เราดำเนินการกับวัตถุหลักจะต้องทำซ้ำสำหรับวัตถุที่ขึ้นต่อกัน

CascadeType.PERSISTหมายความว่าหากเราบันทึกวัตถุหลักลงในฐานข้อมูล ก็จะต้องทำเช่นเดียวกันกับวัตถุที่ขึ้นต่อกัน ตัวอย่าง:


@Entity
@Table(name="employee")
class Employee {
   @Column(name="id")
   public Integer id;
 
   @OneToOne(cascade = CascadeType.PERSIST, mappedBy="task")
   private EmployeeTask task;
}

ตัวอย่างการทำงานกับคลาสนี้:


Employee director = new Employee();
EmployeeTask task = new EmployeeTask();
director.task = task;
 
session.persist(director);
session.flush();

เราบันทึกเฉพาะวัตถุประเภท Employee ซึ่งขึ้นอยู่กับวัตถุ EmployeeTask จะถูกบันทึกลงในฐานข้อมูลโดยอัตโนมัติ

CascadeType.MERGEหมายความว่าหากเราอัปเดตวัตถุหลักในฐานข้อมูล ก็จะต้องทำเช่นเดียวกันกับวัตถุที่ขึ้นต่อกัน

6.4 ลบ ลบ ปลดออก

CascadeType.REMOVEหมายความว่าหากเราลบวัตถุหลักในฐานข้อมูล ก็จะต้องทำเช่นเดียวกันกับวัตถุที่ขึ้นต่อกัน

CascadeType.DELETEหมายความว่าเหมือนกัน เหล่านี้เป็นคำพ้องความหมาย จากข้อกำหนดที่แตกต่างกัน

CascadeType.DETACHหมายความว่าหากเราลบวัตถุหลักออกจากเซสชัน ก็จะต้องทำเช่นเดียวกันกับวัตถุที่ขึ้นต่อกัน ตัวอย่าง:


@Entity
@Table(name="employee")
class Employee {
   @Column(name="id")
   public Integer id;
 
   @OneToOne(cascade = CascadeType.DETACH, mappedBy="task")
   private EmployeeTask task;
}

ตัวอย่างการทำงานกับคลาสนี้:


Employee director = new Employee();
EmployeeTask task = new EmployeeTask();
director.task = task;
director.task = task;
session.flush();
 
assertThat(session.contains(director)).isTrue();
assertThat(session.contains(task)).isTrue();
 
session.detach(director);
 
assertThat(session.contains(director)).isFalse();
assertThat(session.contains(task)).isFalse();

CascadeType.REFRESHและ CascadeType.SAVE_UPDATEทำงานในลักษณะเดียวกับที่เราคาดหวัง - พวกมันทำซ้ำการกระทำที่ทำกับวัตถุหลักไปยังวัตถุที่ขึ้นต่อกัน

6.5 ตัวเลือกการกำจัดเด็กกำพร้า

นอกจากนี้ บางครั้งคุณอาจเจอorphanพารามิเตอร์ นี่เป็นคำย่อสำหรับการกำจัดเด็กกำพร้า ใช้เพื่อให้แน่ใจว่าไม่มีเอนทิตีย่อยที่ไม่มีเอนทิตีหลัก

OneToOne(orphan = true)

หากตั้งค่าพารามิเตอร์นี้เป็นจริง เอนทิตีย่อยจะถูกลบหากหายไปลิงค์ทั้งหมด. Cascade.REMOVEมัน ไม่เหมือนกับ

คุณอาจมีสถานการณ์ที่เอนทิตีหลักหลายรายการอ้างถึงลูกคนเดียว จากนั้นจะเป็นประโยชน์ที่จะไม่ถูกลบพร้อมกับการลบเอนทิตีหลัก แต่ถ้าการอ้างอิงถึงเอนทิตีทั้งหมดจะเป็นโมฆะเท่านั้น

สมมติว่าคุณมีชั้นเรียน:


@Entity
@Table(name="user")
class Employee {
   @Column(name="id")
   public Integer id;
 
   @OneToMany(cascade = CascadeType.ALL, orphan = true)
   @JoinColumn(name = "employee_id")
   private Set<EmployeeTask> tasks = new HashSet<EmployeeTask>();
}


Employee director = session.find(Employee.class, 4);
EmployeeTask task = director.tasks.get(0);
director.tasks.remove(task)
session.persist(director);
session.flush();

วัตถุ EmployeeTask จะถูกลบเนื่องจากไม่มีการอ้างอิงเหลืออยู่ ในเวลาเดียวกัน ไม่มีใครลบวัตถุหลัก

6.6 ตัวเลือกการดึงข้อมูล

ตัวเลือกการดึงข้อมูลช่วยให้คุณควบคุมวิธีการโหลดวัตถุที่ขึ้นต่อกันได้ โดยปกติจะใช้หนึ่งในสองค่า:

  • FetchType.LAZY
  • FetchType.EAGER

นี่เป็นหัวข้อที่น่าสนใจมากซึ่งมีข้อผิดพลาดมากมาย ดังนั้นฉันควรพูดถึงเรื่องนี้ในการบรรยายแยกต่างหาก