JPA: यूनिडायरेक्शनल कई-टू-वन और कैस्केडिंग डिलीट


95

कहो कि मेरा निम्नलिखित की तरह एक अप्रत्यक्ष @ManyToOne संबंध है:

@Entity
public class Parent implements Serializable {

    @Id
    @GeneratedValue
    private long id;
}

@Entity
public class Child implements Serializable {

    @Id
    @GeneratedValue
    private long id;

    @ManyToOne
    @JoinColumn
    private Parent parent;  
}

अगर मेरे माता-पिता P और बच्चे C 1 हैं ... C n P पर वापस जा रहे हैं, तो क्या JPA में बच्चों को स्वचालित रूप से C 1 ... C n हटाने के लिए एक साफ और सुंदर तरीका है, जब P हटाया जाता है (यानी entityManager.remove(P))?

मैं जिस चीज की तलाश कर रहा हूं वह ON DELETE CASCADEएसक्यूएल में एक कार्यक्षमता है ।


1
यहां तक ​​कि अगर केवल 'चाइल्ड' में 'पैरेंट' का संदर्भ होता है (इस तरह से रेफ़रिंग यूनिडायरेक्शनल है) तो क्या आपके लिए '@OneToMany' मैपिंग और 'कैसैड = ऑल' विशेषता के साथ 'चाइल्ड' की सूची जोड़ना मुश्किल है। माता पिता'? मेरा मानना ​​है कि जेपीए को यह संकल्प करना चाहिए कि केवल 1 पक्ष भी कठिन है।
kvDennis

1
@kvDennis, ऐसे मामले हैं जहां आप कसकर युगल को एक तरफ नहीं करना चाहते हैं। उदाहरण के लिए एसीएल-जैसे सेटअप में जहां सुरक्षा अनुमतियाँ पारदर्शी "ऐड-ऑन" हैं
बच्ची

जवाबों:


73

जेपीए में संबंध हमेशा एकतरफा होते हैं, जब तक कि आप माता-पिता को दोनों दिशाओं में बच्चे के साथ नहीं जोड़ते। माता-पिता से बच्चे तक के कैस्केडिंग संचालन को माता-पिता से बच्चे (केवल विपरीत नहीं) के लिए एक संबंध की आवश्यकता होगी।

इसलिए आपको यह करने की आवश्यकता होगी:

  • या तो, द्विदिश @ManyToOneसंबंध को एक द्वि-दिशात्मक @ManyToOneया एक अप्रत्यक्ष रूप से बदल दें @OneToMany। फिर आप REMOVE संचालन को रोक सकते हैं ताकि EntityManager.removeमाता-पिता और बच्चों को हटा दिया जाएगा। आप orphanRemovalकिसी भी अनाथ बच्चों को हटाने के लिए सच्चे के रूप में भी निर्दिष्ट कर सकते हैं , जब माता-पिता के संग्रह में बाल इकाई को शून्य करने के लिए सेट किया जाता है, अर्थात किसी भी माता-पिता के संग्रह में मौजूद नहीं होने पर बच्चे को हटा दें।
  • या, के रूप में बच्चे की मेज में विदेशी कुंजी बाधा निर्दिष्ट करें ON DELETE CASCADE। आपको आह्वान करना होगाEntityManager.clear() कॉल बाद कॉल करना होगा EntityManager.remove(parent)क्योंकि दृढ़ता के संदर्भ को ताज़ा करने की आवश्यकता है - डेटाबेस में हटाए जाने के बाद बच्चे के अस्तित्व को दृढ़ता के संदर्भ में मौजूद नहीं होना चाहिए।

7
क्या JPA एनोटेशन के साथ No2 करने का कोई तरीका है?
user2573153

3
मैं हाइबरनेट xml मैपिंग के साथ No2 कैसे करूं?
arg20

92

यदि आप अपने JPA प्रदाता के रूप में हाइबरनेट का उपयोग कर रहे हैं, तो आप एनोटेशन @OnDelete का उपयोग कर सकते हैं। यह एनोटेशन , DELETE CASCADE पर ट्रिगर के संबंध को जोड़ देगा , जो डेटाबेस से बच्चों को हटाने का प्रतिनिधित्व करता है।

उदाहरण:

public class Parent {

        @Id
        private long id;

}


public class Child {

        @Id
        private long id;

        @ManyToOne
        @OnDelete(action = OnDeleteAction.CASCADE)
        private Parent parent;
}

इस समाधान के साथ बच्चे से माता-पिता के लिए एक अप्रत्यक्ष संबंध स्वचालित रूप से सभी बच्चों को हटाने के लिए पर्याप्त है। इस समाधान के लिए किसी श्रोता आदि की आवश्यकता नहीं है। इसके अलावा क्वेरी से जैसे कि पैरेंट से कहां आईडी = 1 बच्चों को हटा देगा।


4
मैं इसे इस तरह से काम नहीं कर सकता, क्या हाइबरनेट या इस तरह के अन्य विस्तृत उदाहरण का कोई विशिष्ट संस्करण है?
मर्दरी

3
यह कहना मुश्किल है कि यह आपके लिए काम क्यों नहीं कर रहा है। यह काम पाने के लिए आपको स्कीमा को पुन: बनाने की आवश्यकता हो सकती है या आपको मैन्युअल रूप से कैस्केड हटाने को जोड़ना होगा। @OnDelete एनोटेशन थोड़ी देर के लिए लगता है जैसे कि मुझे अनुमान नहीं होगा कि संस्करण एक मुद्दा है।
थॉमस हंज़िकर

10
जवाब के लिए धन्यवाद। त्वरित नोट: डेटाबेस कैस्केड ट्रिगर केवल तभी बनाया जाएगा जब आपने डीडीएल पीढ़ी को हाइबरनेट के माध्यम से सक्षम किया हो। अन्यथा आपको इसे दूसरे तरीके से जोड़ना होगा (उदाहरणार्थ शराबखाना), जो तदर्थ प्रश्नों को सीधे डीबी के खिलाफ चलाने की अनुमति देता है जैसे कि 'डिलीट फ्रॉम पेरेंट व्हेयर आईडी = 1' कैस्केड निष्कासन।
mjj1409

1
यह काम नहीं कर रहा है जब एसोसिएशन @OneToOneकोई विचार है कि इसे कैसे हल किया जाए @OneToOne?
स्टाकेवरफॉल

1
@ThomasHunziker यह अनाथरेमाल के लिए काम नहीं करेगा?
ऑक्सी

13

एक द्वि-दिशात्मक संबंध बनाएं, जैसे:

@Entity
public class Parent implements Serializable {

    @Id
    @GeneratedValue
    private long id;

    @OneToMany(mappedBy = "parent", cascade = CascadeType.REMOVE)
    private Set<Child> children;
}

8
बुरा जवाब, द्विअर्थी रिश्ते JPA में भयानक हैं क्योंकि बड़े बच्चों के सेट पर काम करने में अविश्वसनीय समय लगता है
Enerccio

1
क्या इस बात का सबूत है कि द्विदिश संबंध धीमा हैं?
शलमा

@enerccio क्या होगा यदि द्विदिश संबंध एक-से-एक है? इसके अलावा, कृपया एक लेख दिखाएं जिसमें कहा गया है कि द्वि-दिशात्मक संबंध धीमा हैं? क्या में धीमा हूँ? पुनः प्राप्त करना? को हटाने? अद्यतन करने के?
saran3h

@ saran3h हर ऑपरेशन (ऐड, रिमूव) सभी बच्चों को लोड करेगा, इसलिए यह बहुत बड़ा डेटा लोड है जो बेकार हो सकता है (जैसे मूल्य जोड़ने से सभी बच्चों को डेटाबेस से लोड करने की आवश्यकता नहीं होती है जो वास्तव में यह मैपिंग करता है)।
एनरिको

@Enerccio मुझे लगता है कि हर कोई जॉन्स पर आलसी लोडिंग का उपयोग करता है। तो यह अभी भी कैसा प्रदर्शन है?
saran3h

1

मैंने यूनिडायरेक्शनल @ManytoOne में देखा है, हटाएं उम्मीद के मुताबिक काम न करें। जब माता-पिता को हटा दिया जाता है, तो आदर्श रूप से बच्चे को भी हटा दिया जाना चाहिए, लेकिन केवल माता-पिता को हटा दिया जाता है और बच्चे को हटाया नहीं जाता है और उसे अनाथ के रूप में छोड़ दिया जाता है

इस्तेमाल की जाने वाली तकनीक स्प्रिंग बूट / स्प्रिंग डेटा जेपीए / हाइबरनेट हैं

स्प्रिंट बूट: 2.1.2

स्प्रिंग डेटा जेपीए / हाइबरनेट का उपयोग पंक्ति .eg को हटाने के लिए किया जाता है

parentRepository.delete(parent)

नीचे दिखाए गए अनुसार ParentRepository मानक CRUD रिपॉजिटरी का विस्तार करता है ParentRepository extends CrudRepository<T, ID>

निम्नलिखित मेरी इकाई वर्ग हैं

@Entity(name = child”)
public class Child  {

    @Id
    @GeneratedValue
    private long id;

    @ManyToOne( fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = parent_id", nullable = false)
    @OnDelete(action = OnDeleteAction.CASCADE)
    private Parent parent;
}

@Entity(name = parent”)
public class Parent {

    @Id
    @GeneratedValue
    private long id;

    @Column(nullable = false, length = 50)
    private String firstName;


}

मुझे इस बात का हल मिल गया कि डिलीट क्यों नहीं किया गया। जाहिरा तौर पर हाइबरनेट mysql इंजन -INNODB का उपयोग नहीं कर रहा था, आपको विदेशी कुंजी बाधा उत्पन्न करने के लिए mysql के लिए इंजन INNODB की आवश्यकता है। Application.properties में निम्नलिखित गुणों का उपयोग करके, mysql इंजन INNODB का उपयोग करने के लिए स्प्रिंग बूट / हाइबरनेट बनाता है। इसलिए विदेशी कुंजी बाधा काम करती है और इसलिए कैस्केड को भी हटा दें
रंजेश

पहले की टिप्पणी में मिस्ड प्रॉपर्टी का उपयोग किया गया है। निम्नलिखित वसंत गुणों का उपयोग किया जाता हैspring.jpa.hibernate.use-new-id-generator-mappings=true spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
रंजेश

FYI करें, आपके पास "कोड गलत है। देखेंname= "parent"
अलेक्जेंडर

0

केवल एक पक्ष को हटाने के लिए इस तरह का उपयोग करें

    @ManyToOne(cascade=CascadeType.PERSIST, fetch = FetchType.LAZY)
//  @JoinColumn(name = "qid")
    @JoinColumn(name = "qid", referencedColumnName = "qid", foreignKey = @ForeignKey(name = "qid"), nullable = false)
    // @JsonIgnore
    @JsonBackReference
    private QueueGroup queueGroup;

-1

@Cascade (org.hibernate.annotations.CascadeType.DELETE_ORPHAN)

एनोटेशन ने मेरे लिए काम किया। एक कोशिश हो सकती है

उदाहरण के लिए :-

     public class Parent{
            @Id
            @GeneratedValue(strategy=GenerationType.AUTO)
            @Column(name="cct_id")
            private Integer cct_id;
            @OneToMany(cascade=CascadeType.REMOVE, fetch=FetchType.EAGER,mappedBy="clinicalCareTeam", orphanRemoval=true)
            @Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
            private List<Child> childs;
        }
            public class Child{
            @ManyToOne(fetch=FetchType.EAGER)
            @JoinColumn(name="cct_id")
            private Parent parent;
    }
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.