"ด้านผกผันของสมาคม" ใน JPA OneToMany / ManyToOne แบบสองทิศทางคืออะไร


167

ในส่วนตัวอย่างของการ@OneToManyอ้างอิงคำอธิบายประกอบ JPA :

ตัวอย่าง 1-59 @OneToMany - ระดับลูกค้าพร้อม Generics

@Entity
public class Customer implements Serializable {
    ...
    @OneToMany(cascade=ALL, mappedBy="customer")
    public Set<Order> getOrders() { 
        return orders; 
    }
    ...
}

ตัวอย่าง 1-60 @ManyToOne - คลาสคำสั่งซื้อกับ Generics

@Entity
public class Order implements Serializable {
    ...
    @ManyToOne
    @JoinColumn(name="CUST_ID", nullable=false)
    public Customer getCustomer() { 
        return customer; 
    }
    ...
}

สำหรับฉันแล้วดูเหมือนว่าCustomerกิจการเป็นเจ้าของสมาคม อย่างไรก็ตามในคำอธิบายสำหรับแอmappedByททริบิวในเอกสารเดียวกันมันเขียนไว้ว่า:

หากความสัมพันธ์เป็นแบบสองทิศทางให้ตั้งค่าองค์ประกอบ mappedBy บนด้านผกผัน (ไม่ใช่เจ้าของ) ของการเชื่อมโยงเป็นชื่อของเขตข้อมูลหรือคุณสมบัติที่เป็นเจ้าของความสัมพันธ์ดังตัวอย่างที่ 1-60 แสดง

อย่างไรก็ตามถ้าฉันไม่ผิดดูเหมือนว่าในตัวอย่างที่mappedByระบุไว้ในด้านความเป็นเจ้าของของสมาคมมากกว่าด้านที่ไม่ใช่เจ้าของ

ดังนั้นคำถามของฉันเป็นพื้น:

  1. ในการเชื่อมโยงแบบสองทิศทาง (แบบหนึ่งต่อกลุ่ม / หลายกลุ่ม) สมาคมใดเป็นเจ้าของกิจการ เราจะกำหนดด้านหนึ่งในฐานะเจ้าของได้อย่างไร เราจะกำหนดด้านหลายด้านในฐานะเจ้าของได้อย่างไร

  2. "ฝั่งตรงกันข้ามของสมาคม" มีความหมายว่าอย่างไร? เราจะกำหนดด้านหนึ่งให้เป็นอินเวอร์สได้อย่างไร เราจะกำหนดด้านหลายด้านให้เป็นอินเวอร์สได้อย่างไร


1
ลิงก์ที่คุณระบุล้าสมัยแล้ว โปรดอัปเดต
MartinL

คำตอบ:


306

เพื่อให้เข้าใจสิ่งนี้คุณจะต้องย้อนกลับไป ใน OO ลูกค้าเป็นเจ้าของคำสั่งซื้อ (คำสั่งซื้อคือรายการในวัตถุลูกค้า) ไม่สามารถสั่งซื้อได้หากไม่มีลูกค้า ดังนั้นลูกค้าดูเหมือนจะเป็นเจ้าของคำสั่งซื้อ

แต่ในโลก SQL หนึ่งรายการจะมีตัวชี้ไปยังอีกรายการหนึ่ง เนื่องจากมีลูกค้า 1 รายสำหรับคำสั่งซื้อ N แต่ละคำสั่งซื้อจึงมีรหัสต่างประเทศให้กับลูกค้าที่เป็นของ นี่คือ "การเชื่อมต่อ" และนี่หมายถึงคำสั่งซื้อ "เป็นเจ้าของ" (หรือมีอย่างแท้จริง) การเชื่อมต่อ (ข้อมูล) ตรงข้ามกับ OO / โลกจำลอง

สิ่งนี้อาจช่วยให้เข้าใจ:

public class Customer {
     // This field doesn't exist in the database
     // It is simulated with a SQL query
     // "OO speak": Customer owns the orders
     private List<Order> orders;
}

public class Order {
     // This field actually exists in the DB
     // In a purely OO model, we could omit it
     // "DB speak": Order contains a foreign key to customer
     private Customer customer;
}

ด้านผกผันคือ "เจ้าของ" OO ของวัตถุในกรณีนี้ลูกค้า ลูกค้าไม่มีคอลัมน์ในตารางเพื่อจัดเก็บคำสั่งซื้อดังนั้นคุณต้องบอกว่าที่ใดในตารางคำสั่งซื้อสามารถบันทึกข้อมูลนี้ (ซึ่งเกิดขึ้นผ่านmappedBy)

อีกตัวอย่างทั่วไปคือต้นไม้ที่มีโหนดซึ่งสามารถเป็นได้ทั้งผู้ปกครองและเด็ก ในกรณีนี้ทั้งสองฟิลด์จะใช้ในชั้นเดียว:

public class Node {
    // Again, this is managed by Hibernate.
    // There is no matching column in the database.
    @OneToMany(cascade = CascadeType.ALL) // mappedBy is only necessary when there are two fields with the type "Node"
    private List<Node> children;

    // This field exists in the database.
    // For the OO model, it's not really necessary and in fact
    // some XML implementations omit it to save memory.
    // Of course, that limits your options to navigate the tree.
    @ManyToOne
    private Node parent;
}

สิ่งนี้อธิบายถึง "คีย์ต่างประเทศ" หลายต่อหนึ่งงานออกแบบ มีวิธีที่สองซึ่งใช้ตารางอื่นเพื่อรักษาความสัมพันธ์ นั่นหมายความว่าสำหรับตัวอย่างแรกของเราคุณมีสามตาราง: หนึ่งที่มีลูกค้าหนึ่งที่มีคำสั่งและตารางสองคอลัมน์ที่มีคู่ของคีย์หลัก (customerPK, orderPK)

วิธีการนี้มีความยืดหยุ่นมากกว่าวิธีการข้างต้น (สามารถจัดการแบบหนึ่งต่อหนึ่งแบบตัวต่อตัวแบบตัวต่อตัวและแบบตัวต่อตัว) ราคาก็คือ

  • มันช้าลงเล็กน้อย (ต้องบำรุงรักษาตารางอื่นและเชื่อมใช้สามตารางแทนที่จะเป็นสอง)
  • ไวยากรณ์การรวมมีความซับซ้อนมากขึ้น (ซึ่งอาจน่าเบื่อถ้าคุณต้องเขียนแบบสอบถามจำนวนมากด้วยตนเองเช่นเมื่อคุณพยายามที่จะแก้ไขข้อบกพร่องบางอย่าง)
  • เป็นข้อผิดพลาดได้ง่ายขึ้นเนื่องจากคุณสามารถได้รับผลลัพธ์มากหรือน้อยเกินไปในทันทีเมื่อมีสิ่งผิดพลาดในรหัสที่จัดการตารางการเชื่อมต่อ

นั่นเป็นเหตุผลที่ฉันไม่ค่อยแนะนำวิธีการนี้


36
เพื่อชี้แจง: หลาย ๆ ด้านเป็นเจ้าของ ด้านหนึ่งคือสิ่งที่ตรงกันข้าม คุณไม่มีทางเลือก (พูดจริง)
จอห์น

11
ไม่ไฮเบอร์เนตคิดค้นสิ่งนี้ ฉันไม่ชอบเพราะจะเปิดเผยส่วนหนึ่งของการนำไปใช้กับโมเดล OO ฉันต้องการ@Parentหรือ@Childคำอธิบายประกอบแทนที่จะเป็น "XtoY" เพื่อระบุว่าการเชื่อมต่อมีความหมายอย่างไร (แทนที่จะใช้งาน )
Aaron Digulla

4
@AaronDigulla ทุกครั้งที่ฉันต้องผ่านการแมป OneToMany ฉันมาอ่านคำตอบนี้น่าจะดีที่สุดในเรื่องของ SO
Eugene

7
ว้าว. ถ้าเอกสารกรอบ ORM เท่านั้นมีคำอธิบายที่ดี - มันจะทำให้ทุกอย่างง่ายขึ้นในการกลืน! คำตอบที่ยอดเยี่ยม!
NickJ

2
@klausch: เอกสาร Hibernate กำลังสับสน ไม่ต้องสนใจมัน ดูรหัส SQL ในฐานข้อมูลและวิธีการทำงานของ Foreign Key ถ้าคุณต้องการคุณสามารถเอาสติปัญญากลับบ้านได้: เอกสารเป็นเรื่องโกหก ใช้แหล่งที่มาลุค
Aaron Digulla

41

อย่างไม่น่าเชื่อใน 3 ปีที่ไม่มีใครตอบคำถามที่ยอดเยี่ยมของคุณด้วยตัวอย่างทั้งสองวิธีในการจับคู่ความสัมพันธ์

ตามที่ผู้อื่นกล่าวถึงด้าน "เจ้าของ" ประกอบด้วยตัวชี้ (foreign key) ในฐานข้อมูล คุณสามารถกำหนดด้านใดด้านหนึ่งในฐานะเจ้าของอย่างไรก็ตามถ้าคุณกำหนดด้านหนึ่งในฐานะเจ้าของความสัมพันธ์จะไม่เป็นแบบสองทิศทาง (ด้านตรงกันข้ามหรือ "ด้าน" จำนวนมาก "จะไม่มีความรู้เกี่ยวกับ" เจ้าของ ") สิ่งนี้เป็นที่พึงปรารถนาสำหรับการห่อหุ้ม / การแต่งงานแบบหลวม ๆ :

// "One" Customer owns the associated orders by storing them in a customer_orders join table
public class Customer {
    @OneToMany(cascade = CascadeType.ALL)
    private List<Order> orders;
}

// if the Customer owns the orders using the customer_orders table,
// Order has no knowledge of its Customer
public class Order {
    // @ManyToOne annotation has no "mappedBy" attribute to link bidirectionally
}

โซลูชันการแมปสองทิศทางเพียงอย่างเดียวคือการมีด้าน "หลาย" เป็นเจ้าของตัวชี้ไปยัง "หนึ่ง" และใช้แอตทริบิวต์ @OneToMany "mappedBy" หากไม่มีแอตทริบิวต์ "mappedBy" Hibernate จะคาดหวังว่าการแมปสองครั้ง (ฐานข้อมูลจะมีทั้งคอลัมน์การเข้าร่วมและตารางการเข้าร่วมซึ่งซ้ำซ้อน (มักจะไม่พึงประสงค์)

// "One" Customer as the inverse side of the relationship
public class Customer {
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "customer")
    private List<Order> orders;
}

// "many" orders each own their pointer to a Customer
public class Order {
    @ManyToOne
    private Customer customer;
}

2
ในตัวอย่างทิศทางเดียวของคุณ JPA คาดว่าจะมีตาราง customer_orders พิเศษอยู่ ด้วย JPA2 คุณสามารถใช้คำอธิบายประกอบ @JoinColumn (ซึ่งฉันใช้บ่อย) ในฟิลด์คำสั่งซื้อของลูกค้าเพื่อแสดงคอลัมน์คีย์ต่างประเทศของฐานข้อมูลในตารางคำสั่งที่ควรใช้ วิธีนี้คุณมีความสัมพันธ์แบบทิศทางเดียวใน Java ขณะที่ยังคงมีคอลัมน์คีย์ต่างประเทศในตารางคำสั่งซื้อ ดังนั้นในโลกวัตถุคำสั่งไม่ทราบเกี่ยวกับลูกค้าในขณะที่อยู่ในโลกของฐานข้อมูลลูกค้าไม่ทราบเกี่ยวกับคำสั่งซื้อ
Henno Vermeulen

1
เพื่อความสมบูรณ์ uber คุณสามารถแสดงกรณีแบบสองทิศทางที่ลูกค้าเป็นเจ้าของความสัมพันธ์
HDave

35

เอนทิตีที่มีตารางที่มี foreign key ในฐานข้อมูลเป็นเอนทิตีที่เป็นเจ้าของและอีกตารางที่ถูกชี้ไปที่นั้นคือเอนทิตีผกผัน


30
ง่ายยิ่งขึ้น: เจ้าของเป็นตารางที่มีคอลัมน์ FK
jacktrades

2
คำอธิบายที่ง่ายและดี ด้านใดก็ได้ที่สามารถทำให้เจ้าของ หากเราใช้ mappedBy ใน Order.java ในฟิลด์ลูกค้า <ลบ mappedby จาก Customer.java> จากนั้นตารางใหม่จะถูกสร้างขึ้นเช่น Order_Customer ซึ่งจะมี 2 คอลัมน์ ORDER_ID และ CUSTOMER_ID
HakunaMatata

14

กฎง่ายๆของความสัมพันธ์แบบสองทิศทาง:

1. สำหรับความสัมพันธ์แบบสองทิศทางต่อหนึ่งหลาย ๆ ด้านหลายด้านเป็นความสัมพันธ์ที่เป็นเจ้าของเสมอ ตัวอย่าง: 1 ห้องมีหลายคน (คนเป็นหนึ่งห้องเท่านั้น) -> ด้านการเป็นเจ้าของคือบุคคล

2. สำหรับความสัมพันธ์แบบสองทิศทางต่อหนึ่งด้านการเป็นเจ้าของจะสอดคล้องกับด้านที่มีรหัสต่างประเทศที่เกี่ยวข้อง

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

หวังว่าจะช่วยคุณได้


ทำไมเราต้องมีเจ้าของและสิ่งที่ตรงกันข้ามเลย? เรามีแนวคิดที่มีความหมายของด้านเดียวและหลายด้านอยู่แล้วและไม่สำคัญว่าใครจะเป็นเจ้าของในหลาย ๆ สถานการณ์ การตัดสินใจคืออะไร เป็นเรื่องยากที่จะเชื่อว่าใครบางคนที่มีสติปัญญาด้านซ้ายในฐานะวิศวกรฐานข้อมูลตัดสินใจที่จะนำแนวคิดที่ซ้ำซ้อนเหล่านี้มาใช้
Dan Cancro

3

สำหรับลูกค้าสองประเภท Entity และการสั่งซื้อไฮเบอร์เนตจะสร้างสองตาราง

กรณีที่เป็นไปได้:

  1. mappedBy ไม่ได้ใช้ใน Customer.java และ Order.java Class แล้ว ->

    ที่ด้านลูกค้าจะมีการสร้างตารางใหม่ [name = CUSTOMER_ORDER] ซึ่งจะทำการจับคู่กับ CUSTOMER_ID และ ORDER_ID นี่คือกุญแจหลักของลูกค้าและตารางการสั่งซื้อ ที่ด้านการสั่งซื้อจำเป็นต้องมีคอลัมน์เพิ่มเติมเพื่อบันทึกการจับคู่ระเบียน Customer_ID ที่สอดคล้องกัน

  2. mappedBy ถูกใช้ใน Customer.java [ตามที่ระบุในคำสั่งปัญหา] ตอนนี้ไม่ได้สร้างตารางเพิ่มเติม [CUSTOMER_ORDER] เพียงหนึ่งคอลัมน์ในตารางการสั่งซื้อ

  3. mappedby ใช้ใน Order.java ขณะนี้ตารางเพิ่มเติมจะถูกสร้างขึ้นโดย hibernate [name = CUSTOMER_ORDER] ตารางการสั่งซื้อจะไม่มีคอลัมน์เพิ่มเติม [Customer_ID] สำหรับการจับคู่

ฝ่ายใดฝ่ายหนึ่งสามารถทำให้เจ้าของความสัมพันธ์ แต่ดีกว่าที่จะเลือก xxxToOne ด้าน

ผลการเข้ารหัส -> เฉพาะด้านเอนทิตี้ของสามารถเปลี่ยนสถานะความสัมพันธ์ ในตัวอย่างด้านล่างคลาส BoyFriend เป็นเจ้าของความสัมพันธ์ แม้ว่าแฟนอยากจะเลิกกันเธอก็ทำไม่ได้

import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;

@Entity
@Table(name = "BoyFriend21")
public class BoyFriend21 {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "Boy_ID")
    @SequenceGenerator(name = "Boy_ID", sequenceName = "Boy_ID_SEQUENCER", initialValue = 10,allocationSize = 1)
    private Integer id;

    @Column(name = "BOY_NAME")
    private String name;

    @OneToOne(cascade = { CascadeType.ALL })
    private GirlFriend21 girlFriend;

    public BoyFriend21(String name) {
        this.name = name;
    }

    public BoyFriend21() {
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public BoyFriend21(String name, GirlFriend21 girlFriend) {
        this.name = name;
        this.girlFriend = girlFriend;
    }

    public GirlFriend21 getGirlFriend() {
        return girlFriend;
    }

    public void setGirlFriend(GirlFriend21 girlFriend) {
        this.girlFriend = girlFriend;
    }
}

import org.hibernate.annotations.*;
import javax.persistence.*;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.Table;
import java.util.ArrayList;
import java.util.List;

@Entity 
@Table(name = "GirlFriend21")
public class GirlFriend21 {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "Girl_ID")
    @SequenceGenerator(name = "Girl_ID", sequenceName = "Girl_ID_SEQUENCER", initialValue = 10,allocationSize = 1)
    private Integer id;

    @Column(name = "GIRL_NAME")
    private String name;

    @OneToOne(cascade = {CascadeType.ALL},mappedBy = "girlFriend")
    private BoyFriend21 boyFriends = new BoyFriend21();

    public GirlFriend21() {
    }

    public GirlFriend21(String name) {
        this.name = name;
    }


    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public GirlFriend21(String name, BoyFriend21 boyFriends) {
        this.name = name;
        this.boyFriends = boyFriends;
    }

    public BoyFriend21 getBoyFriends() {
        return boyFriends;
    }

    public void setBoyFriends(BoyFriend21 boyFriends) {
        this.boyFriends = boyFriends;
    }
}


import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import java.util.Arrays;

public class Main578_DS {

    public static void main(String[] args) {
        final Configuration configuration = new Configuration();
         try {
             configuration.configure("hibernate.cfg.xml");
         } catch (HibernateException e) {
             throw new RuntimeException(e);
         }
        final SessionFactory sessionFactory = configuration.buildSessionFactory();
        final Session session = sessionFactory.openSession();
        session.beginTransaction();

        final BoyFriend21 clinton = new BoyFriend21("Bill Clinton");
        final GirlFriend21 monica = new GirlFriend21("monica lewinsky");

        clinton.setGirlFriend(monica);
        session.save(clinton);

        session.getTransaction().commit();
        session.close();
    }
}

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import java.util.List;

public class Main578_Modify {

    public static void main(String[] args) {
        final Configuration configuration = new Configuration();
        try {
            configuration.configure("hibernate.cfg.xml");
        } catch (HibernateException e) {
            throw new RuntimeException(e);
        }
        final SessionFactory sessionFactory = configuration.buildSessionFactory();
        final Session session1 = sessionFactory.openSession();
        session1.beginTransaction();

        GirlFriend21 monica = (GirlFriend21)session1.load(GirlFriend21.class,10);  // Monica lewinsky record has id  10.
        BoyFriend21 boyfriend = monica.getBoyFriends();
        System.out.println(boyfriend.getName()); // It will print  Clinton Name
        monica.setBoyFriends(null); // It will not impact relationship

        session1.getTransaction().commit();
        session1.close();

        final Session session2 = sessionFactory.openSession();
        session2.beginTransaction();

        BoyFriend21 clinton = (BoyFriend21)session2.load(BoyFriend21.class,10);  // Bill clinton record

        GirlFriend21 girlfriend = clinton.getGirlFriend();
        System.out.println(girlfriend.getName()); // It will print Monica name.
        //But if Clinton[Who owns the relationship as per "mappedby" rule can break this]
        clinton.setGirlFriend(null);
        // Now if Monica tries to check BoyFriend Details, she will find Clinton is no more her boyFriend
        session2.getTransaction().commit();
        session2.close();

        final Session session3 = sessionFactory.openSession();
        session1.beginTransaction();

        monica = (GirlFriend21)session3.load(GirlFriend21.class,10);  // Monica lewinsky record has id  10.
        boyfriend = monica.getBoyFriends();

        System.out.println(boyfriend.getName()); // Does not print Clinton Name

        session3.getTransaction().commit();
        session3.close();
    }
}

1

ความสัมพันธ์ของตารางเทียบกับความสัมพันธ์เอนทิตี

ในระบบฐานข้อมูลเชิงสัมพันธ์สามารถมีความสัมพันธ์ของตารางได้สามประเภทเท่านั้น:

  • ตัวต่อตัว (ผ่านคอลัมน์ Foreign Key)
  • หนึ่งต่อหนึ่ง (ผ่านคีย์หลักที่แชร์)
  • หลายต่อหลายคน (ผ่านตารางลิงก์ที่มี Foreign Keys สองตัวที่อ้างอิงถึงตารางหลักแยกกันสองตาราง)

ดังนั้นone-to-manyความสัมพันธ์ของตารางจึงมีลักษณะดังนี้:

<code> ความสัมพันธ์ของตารางแบบตัวต่อตัว </code>

โปรดทราบว่าความสัมพันธ์จะขึ้นอยู่กับคอลัมน์ Foreign Key (เช่นpost_id) ในตารางลูก

ดังนั้นจึงมีแหล่งความจริงเดียวเมื่อพูดถึงการจัดการone-to-manyความสัมพันธ์ของตาราง

ตอนนี้ถ้าคุณใช้ความสัมพันธ์เอนทิตีแบบสองทิศทางที่แมปกับone-to-manyความสัมพันธ์ของตารางที่เราเห็นก่อนหน้านี้:

<code> การเชื่อมโยงเอนทิตีแบบ One-To-Many </code> แบบสองทิศทาง

หากคุณดูที่แผนภาพด้านบนคุณจะเห็นว่ามีสองวิธีในการจัดการความสัมพันธ์นี้

ในPostนิติบุคคลคุณมีการcommentsรวบรวม:

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

และในPostCommentการpostเชื่อมโยงเป็นแมปดังต่อไปนี้:

@ManyToOne(
    fetch = FetchType.LAZY
)
@JoinColumn(name = "post_id")
private Post post;

ดังนั้นคุณมีสองด้านที่สามารถเปลี่ยนการเชื่อมโยงเอนทิตี:

  • โดยการเพิ่มรายการในcommentsคอลเล็กชันpost_commentลูกแถวใหม่ควรเชื่อมโยงกับpostเอนทิตีหลักผ่านpost_idคอลัมน์
  • โดยการตั้งค่าpostคุณสมบัติของPostCommentเอนทิตีpost_idคอลัมน์ควรมีการปรับปรุงเช่นกัน

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

MappedBy (aka ด้านผกผัน)

mappedByแอตทริบิวต์บอกว่า@ManyToOneด้านเป็นค่าใช้จ่ายในการจัดการคอลัมน์ต่างประเทศที่สำคัญและคอลเลกชันจะใช้เพื่อดึงข้อมูลหน่วยงานของเด็กและการเปลี่ยนแปลงสถานะน้ำตกปกครองนิติบุคคลให้กับเด็ก ๆ (เช่นการเอาผู้ปกครองก็ควรเอาหน่วยงานเด็ก)

มันเรียกว่าด้านผกผันเพราะมันอ้างอิงคุณสมบัติลูกนิติบุคคลที่จัดการความสัมพันธ์ของตารางนี้

ประสานทั้งสองด้านของความสัมพันธ์แบบสองทิศทาง

ตอนนี้แม้ว่าคุณจะกำหนดmappedByแอตทริบิวต์และการ@ManyToOneเชื่อมโยงฝั่งเด็กจัดการคอลัมน์ Foreign Key คุณยังคงต้องซิงโครไนซ์ทั้งสองด้านของการเชื่อมโยงแบบสองทิศทาง

วิธีที่ดีที่สุดในการทำเช่นนั้นคือการเพิ่มวิธีการอรรถประโยชน์ทั้งสองนี้:

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

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

กระบวนการaddCommentและremoveCommentวิธีการทำให้มั่นใจได้ว่าทั้งสองฝ่ายได้รับการทำข้อมูลให้ตรงกัน ดังนั้นถ้าเราเพิ่มเอนทิตีลูกเอนทิตีลูกต้องชี้ไปที่พาเรนต์และเอนทิตีพาเรนต์ควรมีลูกที่อยู่ในคอลเลกชันลูก

สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับวิธีที่ดีที่สุดในการประสานทุกประเภทสองทิศทางสมาคมนิติบุคคลตรวจสอบบทความนี้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.