JPA @OneToMany एसोसिएशन का उपयोग करते समय @JoinColumn और mappedBy के बीच क्या अंतर है


516

के बीच क्या अंतर है:

@Entity
public class Company {

    @OneToMany(cascade = CascadeType.ALL , fetch = FetchType.LAZY)
    @JoinColumn(name = "companyIdRef", referencedColumnName = "companyId")
    private List<Branch> branches;
    ...
}

तथा

@Entity
public class Company {

    @OneToMany(cascade = CascadeType.ALL , fetch = FetchType.LAZY, mappedBy = "companyIdRef")
    private List<Branch> branches;
    ...
}

1
यह भी देखें कि ओआरएम मैपिंग प्रश्न में शामिल मुद्दों की वास्तव में अच्छी व्याख्या के लिए मालिकाना पक्ष क्या है
11

जवाबों:


545

एनोटेशन @JoinColumnइंगित करता है कि यह इकाई संबंध का स्वामी है (अर्थात: संबंधित तालिका में संदर्भित तालिका के लिए एक विदेशी कुंजी के साथ एक स्तंभ है), जबकि विशेषता mappedByइंगित करती है कि इस पक्ष में इकाई संबंध का व्युत्क्रम है, और मालिक "अन्य" इकाई में रहता है। इसका मतलब यह भी है कि आप उस वर्ग से अन्य तालिका तक पहुंच सकते हैं जिसे आपने "मैप्डबी" (पूरी तरह से द्विदिश संबंध) के साथ एनोटेट किया है।

विशेष रूप से, प्रश्न में कोड के लिए सही एनोटेशन इस तरह दिखेगा:

@Entity
public class Company {
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "company")
    private List<Branch> branches;
}

@Entity
public class Branch {
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "companyId")
    private Company company;
}

3
दोनों मामलों में ब्रांच के पास कंपनी आईडी है।
Mykhaylo Adamovych

3
कंपनी तालिका में संदर्भित तालिका के लिए एक विदेशी कुंजी के साथ एक कॉलम नहीं है - शाखा ने कंपनी को रेफरी किया है .. आप क्यों कह रहे हैं "संबंधित तालिका में संदर्भित तालिका के लिए एक विदेशी कुंजी वाला कॉलम है"? क्या आप कुछ और pls बता सकते हैं।
Mykhaylo Adamovych

13
@MykhayloAdamovych मैंने नमूना कोड के साथ अपना उत्तर अपडेट किया। ध्यान दें कि इसका उपयोग करने @JoinColumnमें गलती हैCompany
óscar López

10
@ मेखायलोअदमोविक: नहीं, यह वास्तव में बिल्कुल सही नहीं है। यदि आपके Branchपास कोई संपत्ति नहीं है जो संदर्भ देता है Company, लेकिन अंतर्निहित तालिका में एक स्तंभ है जो करता है, तो आप @JoinTableइसे मैप करने के लिए उपयोग कर सकते हैं । यह एक असामान्य स्थिति है, क्योंकि आप सामान्य रूप से कॉलम को उस ऑब्जेक्ट में मैप करेंगे जो उसकी तालिका से मेल खाती है, लेकिन ऐसा हो सकता है, और यह पूरी तरह से वैध है।
टॉम एंडरसन

4
यह ORM के पसंद न करने का एक और कारण है। प्रलेखन अक्सर बहुत नीरस है, और मेरी किताबों में, यह बहुत अधिक जादू क्षेत्र पर शोक मना रहा है। मैं इस समस्या से जूझ रहा हूं और जब शब्द के लिए शब्द का पालन किया जाता है @OneToOne, तो बच्चे की पंक्तियों nullको उनके FKey कॉलम में अद्यतन किया जाता है जो माता-पिता को संदर्भित करता है।
आशेश

225

@JoinColumnरिश्ते के दोनों किनारों पर इस्तेमाल किया जा सकता है। प्रश्न पक्ष (दुर्लभ मामले) का उपयोग @JoinColumnकरने के बारे में था @OneToMany। और यहाँ बिंदु भौतिक जानकारी दोहराव (कॉलम नाम) के साथ है साथ में अनुकूलित एसक्यूएल क्वेरी नहीं है जो कुछ अतिरिक्त UPDATEबयानों का उत्पादन करेगा

प्रलेखन के अनुसार :

चूँकि कई एक से (लगभग) हमेशा जेपीए युक्ति में एक द्विदिश संबंध के मालिक पक्ष होते हैं, एक से कई संघों द्वारा एनोटेट किया जाता है@OneToMany(mappedBy=...)

@Entity
public class Troop {
    @OneToMany(mappedBy="troop")
    public Set<Soldier> getSoldiers() {
    ...
}

@Entity
public class Soldier {
    @ManyToOne
    @JoinColumn(name="troop_fk")
    public Troop getTroop() {
    ...
} 

TroopSoldierसैन्य संपत्ति के माध्यम से कई संबंधों के लिए एक द्विदिश है । आपको mappedByपक्ष में किसी भी भौतिक मानचित्रण को परिभाषित नहीं करना चाहिए (नहीं करना चाहिए) ।

एक-से-एक के साथ एक-से-एक पक्ष के मालिक के रूप में कई को मैप करने के लिए , आपको mappedByतत्व को निकालना होगा और कई को एक के @JoinColumnरूप में insertableऔर updatableगलत पर सेट करना होगा । यह समाधान अनुकूलित नहीं है और कुछ अतिरिक्त UPDATEबयानों का उत्पादन करेगा ।

@Entity
public class Troop {
    @OneToMany
    @JoinColumn(name="troop_fk") //we need to duplicate the physical information
    public Set<Soldier> getSoldiers() {
    ...
}

@Entity
public class Soldier {
    @ManyToOne
    @JoinColumn(name="troop_fk", insertable=false, updatable=false)
    public Troop getTroop() {
    ...
}

1
मैं यह पता लगाने में सक्षम नहीं हूं कि ट्रूप आपके दूसरे स्निपेट में मालिक कैसे हो सकता है, सोल्जर अभी भी मालिक है, क्योंकि इसमें ट्रूप के लिए विदेशी कुंजी संदर्भित है। (मैं mysql का उपयोग कर रहा हूं, मैंने आपके दृष्टिकोण से जांच की)।
अखिलेश

10
आपके उदाहरण में एनोटेशन mappedBy="troop"किस क्षेत्र को संदर्भित करता है?
फ्रैक्टालिस्ट

5
@ फ्रैक्टलिस्ट एनोटेशन का mappedBy="troop"अर्थ है क्लास सोल्जर में संपत्ति की टुकड़ी। प्रॉपर्टी के ऊपर कोड दिखाई नहीं देता है क्योंकि यहाँ Mykhaylo ने इसे छोड़ दिया था, लेकिन आप getTroop () द्वारा इसके अस्तित्व को घटा सकते हैं। Lscar López के उत्तर की जाँच करें , यह बहुत स्पष्ट है और आपको बात मिल जाएगी।
निकोलिमोइरी

1
यह उदाहरण जेपीए 2 विनिर्देश का दुरुपयोग है। यदि लेखक का उद्देश्य द्विदिश संबंध बनाना है तो उसे माता-पिता की ओर से मैप किए गए का उपयोग करना चाहिए और चाइल्ड की तरफ JoinColumn (यदि आवश्यक हो)। प्रस्तुत दृष्टिकोण के साथ हम 2 अप्रत्यक्ष संबंध प्राप्त कर रहे हैं: OneToMany और ManyToOne जो स्वतंत्र हैं लेकिन सिर्फ भाग्य से (दुरुपयोग से अधिक) उन 2 संबंधों को एक ही विदेशी कुंजी का उपयोग करके परिभाषित किया गया है
aurelije

1
यदि आप JPA 2.x का उपयोग कर रहे हैं, तो नीचे दिया गया मेरा उत्तर थोड़ा साफ है। हालांकि मैं दोनों मार्गों की कोशिश कर रहा हूं और देख रहा हूं कि जब टेबल उत्पन्न होता है तो हाइबरनेट क्या करता है। यदि आप एक नई परियोजना पर हैं, तो जो भी पीढ़ी आपको लगता है कि आपकी आवश्यकताओं को पूरा करती है। यदि आप एक विरासत डेटाबेस पर हैं और संरचना को बदलना नहीं चाहते हैं, तो जो भी आपके स्कीमा से मेल खाता है उसे चुनें।
स्नेकसी

65

चूंकि यह एक बहुत ही सामान्य प्रश्न है, इसलिए मैंने यह लेख लिखा है , जिस पर यह उत्तर आधारित है।

यूनिडायरेक्शनल एक से कई एसोसिएशन

जैसा कि मैंने इस लेख में बताया है , यदि आप @OneToManyएनोटेशन का उपयोग करते हैं @JoinColumn, तो आपके पास एक यूनिडायरेक्शनल एसोसिएशन है, जैसे मूल Postइकाई और बच्चे PostCommentके बीच निम्न आरेख में:

यूनिडायरेक्शनल एक से कई एसोसिएशन

यूनिडायरेक्शनल वन-टू-कई एसोसिएशन का उपयोग करते समय, केवल पैरेंट साइड एसोसिएशन को मैप करता है।

इस उदाहरण में, केवल Postसंस्था @OneToManyबाल PostCommentसंस्था से जुड़ाव को परिभाषित करेगी :

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

द्विदिश एक से कई संघ

यदि आप विशेषता सेट के @OneToManyसाथ उपयोग करते हैं mappedBy, तो आपके पास एक द्विदिश संघ है। हमारे मामले में, दोनों Postसंस्था के पास PostCommentबाल संस्थाओं का एक संग्रह है , और बच्चे PostCommentइकाई के पास मूल Postसंस्था के लिए एक संदर्भ है , जैसा कि निम्नलिखित चित्र द्वारा दर्शाया गया है:

द्विदिश एक से कई संघ

में PostCommentइकाई, postइस प्रकार इकाई संपत्ति मैप किया गया है:

@ManyToOne(fetch = FetchType.LAZY)
private Post post;

इसका कारण हमने स्पष्ट रूप से fetchविशेषता को निर्धारित किया FetchType.LAZYहै, क्योंकि डिफ़ॉल्ट रूप से, सभी @ManyToOneऔर @OneToOneसंघों को उत्सुकता से प्राप्त किया जाता है, जो एन + क्वेरी मुद्दों का कारण बन सकता है। इस विषय के बारे में अधिक जानकारी के लिए, इस लेख को देखें

में Postइकाई, commentsइस प्रकार संघ मैप किया गया है:

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

एनोटेशन की mappedByविशेषता बाल इकाई में संपत्ति का @OneToManyसंदर्भ देती postहै PostComment, और, इस तरह, हाइबरनेट को पता है कि द्विदिश संघ को @ManyToOneपक्ष द्वारा नियंत्रित किया जाता है , जो कि विदेशी कुंजी स्तंभ मूल्य के प्रबंधन के प्रभारी हैं, यह तालिका संबंध पर आधारित है।

एक द्विदिश संघ के लिए, आपके पास दो उपयोगिता विधियाँ होनी चाहिए, जैसे addChildऔर removeChild:

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

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

ये दो विधियां यह सुनिश्चित करती हैं कि द्विदिश संघ के दोनों पक्ष एकसमान हैं। दोनों सिरों को सिंक्रनाइज़ किए बिना, हाइबरनेट यह गारंटी नहीं देता है कि एसोसिएशन राज्य परिवर्तन डेटाबेस को प्रचारित करेगा।

जेपीए और हाइबरनेट के साथ द्विदिश संघों को सिंक्रनाइज़ करने के लिए सबसे अच्छा वाट के बारे में अधिक जानकारी के लिए, इस लेख को देखें

कौन सा चुनना है?

दिशाहीन @OneToManyसंघ बहुत अच्छा प्रदर्शन नहीं करता है, तो आप इसे से बचना चाहिए।

आप द्विदिश@OneToMany का उपयोग करने से बेहतर हैं जो अधिक कुशल है


32

एनोटेशन मैप्डबाय का उपयोग हमेशा द्वि-दिशात्मक संबंध के पेरेंट साइड (कंपनी वर्ग) में किया जाना चाहिए, इस मामले में यह चाइल्ड क्लास (ब्रांच क्लास) के सदस्य चर 'कंपनी' की ओर इशारा करते हुए कंपनी वर्ग में होना चाहिए।

एनोटेशन @JoinColumn का उपयोग एक इकाई संघ में शामिल होने के लिए एक मैप किए गए कॉलम को निर्दिष्ट करने के लिए किया जाता है, इस एनोटेशन का उपयोग किसी भी वर्ग (पैरेंट या चाइल्ड) में किया जा सकता है, लेकिन इसका उपयोग केवल एक पक्ष में किया जाना चाहिए (या तो पैरेंट क्लास में या चाइल्ड क्लास में नहीं दोनों में) इस मामले में मैंने इसे द्वि-दिशात्मक संबंध के चाइल्ड साइड (शाखा वर्ग) में उपयोग किया, जो शाखा वर्ग में विदेशी कुंजी को दर्शाता है।

नीचे काम करने का उदाहरण है:

मूल वर्ग, कंपनी

@Entity
public class Company {


    private int companyId;
    private String companyName;
    private List<Branch> branches;

    @Id
    @GeneratedValue
    @Column(name="COMPANY_ID")
    public int getCompanyId() {
        return companyId;
    }

    public void setCompanyId(int companyId) {
        this.companyId = companyId;
    }

    @Column(name="COMPANY_NAME")
    public String getCompanyName() {
        return companyName;
    }

    public void setCompanyName(String companyName) {
        this.companyName = companyName;
    }

    @OneToMany(fetch=FetchType.LAZY,cascade=CascadeType.ALL,mappedBy="company")
    public List<Branch> getBranches() {
        return branches;
    }

    public void setBranches(List<Branch> branches) {
        this.branches = branches;
    }


}

बालक वर्ग, शाखा

@Entity
public class Branch {

    private int branchId;
    private String branchName;
    private Company company;

    @Id
    @GeneratedValue
    @Column(name="BRANCH_ID")
    public int getBranchId() {
        return branchId;
    }

    public void setBranchId(int branchId) {
        this.branchId = branchId;
    }

    @Column(name="BRANCH_NAME")
    public String getBranchName() {
        return branchName;
    }

    public void setBranchName(String branchName) {
        this.branchName = branchName;
    }

    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="COMPANY_ID")
    public Company getCompany() {
        return company;
    }

    public void setCompany(Company company) {
        this.company = company;
    }


}

20

मैं केवल यह जोड़ना चाहूंगा कि @JoinColumnहमेशा भौतिक सूचना स्थान से संबंधित नहीं होना चाहिए क्योंकि यह उत्तर बताता है। आप को जोड़ सकते हैं @JoinColumnके साथ @OneToManyभले ही माता-पिता की मेज बच्चे मेज की ओर इशारा करते कोई तालिका डेटा है।

JPA में यूनिडायरेक्शनल OneToMany संबंध को कैसे परिभाषित करें

यूनिडायरेक्शनल OneToMany, No Inverse ManyToOne, No Join Table

यह केवल JPA 2.x+हालांकि में उपलब्ध होने लगता है । यह उन स्थितियों के लिए उपयोगी है जहां आप चाहते हैं कि बच्चे की कक्षा में सिर्फ माता-पिता की आईडी हो, संदर्भ पर पूर्ण नहीं।


आप सही हैं, यूनिडायरेक्शनल OneToMany के लिए बिना ज्वाइन टेबल के सपोर्ट JPA2 में पेश किया गया है
aurelije

17

मैं यहाँ herescar López द्वारा स्वीकृत उत्तर से असहमत हूँ। वह जवाब गलत है!

ऐसा नहीं है @JoinColumnजो इंगित करता है कि यह संस्था रिश्ते का मालिक है। इसके बजाय, यह @ManyToOneएनोटेशन है जो ऐसा करता है (उसके उदाहरण में)।

संबंध एनोटेशन जैसे @ManyToOne, @OneToManyऔर @ManyToManyजेपीए / हाइबरनेट को मैपिंग बनाने के लिए कहते हैं। डिफ़ॉल्ट रूप से, यह एक अलग ज्वाइन टेबल के माध्यम से किया जाता है।


@JoinColumn

के प्रयोजन के @JoinColumnलिए एक बनाने के लिए है स्तंभ में शामिल होने अगर एक पहले से ही मौजूद नहीं है। यदि ऐसा होता है, तो इस एनोटेशन का उपयोग जॉइन कॉलम को नाम देने के लिए किया जा सकता है ।


MappedBy

MappedByजेपीए को निर्देश देने के लिए पैरामीटर का उद्देश्य है : एक और ज्वाइन टेबल न बनाएं क्योंकि इस संबंध की विपरीत इकाई द्वारा संबंध पहले से ही मैप किया जा रहा है ।



याद रखें: MappedByसंबंध एनोटेशन की एक संपत्ति है जिसका उद्देश्य दो संस्थाओं से संबंधित एक तंत्र उत्पन्न करना है जो डिफ़ॉल्ट रूप से वे एक सम्मिलित तालिका बनाकर करते हैं। MappedByएक दिशा में उस प्रक्रिया को रोक देता है।

उपयोग न करने वाली इकाई को संबंध MappedByका स्वामी कहा जाता है क्योंकि मैपिंग के मैकेनिक्स को विदेशी कुंजी क्षेत्र के खिलाफ तीन मैपिंग एनोटेशन में से एक के उपयोग के माध्यम से अपनी कक्षा के भीतर निर्धारित किया जाता है। यह न केवल मानचित्रण की प्रकृति को निर्दिष्ट करता है, बल्कि एक सम्मिलित तालिका के निर्माण का भी निर्देश देता है। इसके अलावा, ज्वाइंट टेबल को दबाने का विकल्प भी विदेशी कुंजी पर @JoinColumn एनोटेशन को लागू करने से मौजूद है जो इसे मालिक इकाई के टेबल के अंदर रखता है।

इसलिए सारांश में: @JoinColumnया तो एक नया जॉइन कॉलम बनाता है या किसी मौजूदा का नाम बदल देता है; जबकि MappedByपैरामीटर के लिए एक के माध्यम से या तो एक मानचित्रण बनाने के लिए अन्य (बच्चे) वर्ग के संबंध एनोटेशन के साथ सहयोग करते हुए काम करता है टेबल या मालिक संस्था की संबद्ध तालिका में एक विदेशी कुंजी स्तंभ बनाने के द्वारा में शामिल हो।

यह MapppedByसमझने के लिए कि कैसे काम करता है, नीचे दिए गए कोड पर विचार करें। यदि MappedByपैरामीटर हटाए जाने थे, तो हाइबरनेट वास्तव में दो जुड़ने वाली तालिकाओं का निर्माण करेगा! क्यों? क्योंकि कई-कई रिश्तों में एक समरूपता है और हाइबरनेट में एक दिशा को दूसरे पर चुनने के लिए कोई तर्क नहीं है।

इसलिए हम MappedByहाइबरनेट बताने के लिए उपयोग करते हैं, हमने दो संस्थाओं के बीच संबंधों के मानचित्रण को निर्धारित करने के लिए अन्य इकाई को चुना है।

@Entity
public class Driver {
    @ManyToMany(mappedBy = "drivers")
    private List<Cars> cars;
}

@Entity
public class Cars {
    @ManyToMany
    private List<Drivers> drivers;
}

मालिक वर्ग में @JoinColumn (नाम = "ड्राइवरआईडी") को जोड़ना, नीचे दी गई तालिका के निर्माण को रोक देगा और इसके बजाय मैपिंग का निर्माण करने के लिए कार तालिका में ड्राइवर का विदेशी कुंजी स्तंभ बनाएँ:

@Entity
public class Driver {
    @ManyToMany(mappedBy = "drivers")
    private List<Cars> cars;
}

@Entity
public class Cars {
    @ManyToMany
    @JoinColumn(name = "driverID")
    private List<Drivers> drivers;
}

1

जेपीए एक स्तरित एपीआई है, विभिन्न स्तरों के अपने एनोटेशन हैं। उच्चतम स्तर 1 (1) इकाई स्तर है जो लगातार कक्षाओं का वर्णन करता है, तो आपके पास (2) संबंधपरक डेटाबेस स्तर है जो मानते हैं कि निकाय एक रिलेशनल डेटाबेस में मैप किए जाते हैं और (3) जावा मॉडल।

स्तर 1 एनोटेशन: @Entity, @Id, @OneToOne, @OneToMany, @ManyToOne, @ManyToMany। आप अकेले इन उच्च स्तरीय एनोटेशन का उपयोग करके अपने आवेदन में दृढ़ता का परिचय दे सकते हैं। लेकिन फिर आपको जेपीए द्वारा की गई मान्यताओं के अनुसार अपना डेटाबेस बनाना होगा। ये एनोटेशन इकाई / संबंध मॉडल को निर्दिष्ट करते हैं।

स्तर 2 एनोटेशन: @Table, @Column, @JoinColumn, ... संस्थाओं / संपत्ति से मानचित्रण रिलेशनल डेटाबेस तालिकाओं के लिए प्रभाव / स्तंभों अगर आप जेपीए के चूक से संतुष्ट नहीं हैं या यदि आप एक मौजूदा डेटाबेस के लिए मैप करने की आवश्यकता है। इन एनोटेशन को कार्यान्वयन एनोटेशन के रूप में देखा जा सकता है, वे निर्दिष्ट करते हैं कि मैपिंग कैसे की जानी चाहिए।

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

सवालों के जवाब देने के लिए: @OneToMany/ mappedByयह सबसे अच्छा है क्योंकि यह केवल इकाई डोमेन से एनोटेशन का उपयोग करता है। @oneToMany/ @JoinColumnभी ठीक है, लेकिन यह एक कार्यान्वयन एनोटेशन जहां इस सख्ती से आवश्यक नहीं है का उपयोग करता है।


1

मुझे इसे सरल बनाने दें।
आप मैपिंग के बावजूद दोनों तरफ @JoinColumn का उपयोग कर सकते हैं ।

इसे तीन मामलों में विभाजित करते हैं।
1) शाखा से कंपनी तक यूनी-दिशात्मक मानचित्रण।
2) कंपनी से शाखा तक द्वि-दिशा मानचित्रण।
3) कंपनी से शाखा तक केवल यूनी-दिशात्मक मानचित्रण।

तो कोई भी उपयोग-मामला इस तीन श्रेणियों के अंतर्गत आएगा। तो चलिए आपको बताते हैं कि @JoinColumn और mappedBy का उपयोग कैसे करें ।
1) शाखा से कंपनी तक यूनी-दिशात्मक मानचित्रण। ब्रांच टेबल में JoinColumn का
उपयोग करें । 2) कंपनी से शाखा तक द्वि-दिशा मानचित्रण। कंपनी की तालिका में मैप किए गए का उपयोग करें जैसा कि @Mykhaylo Adamovych के उत्तर द्वारा वर्णित है। 3) कंपनी से शाखा तक यूनी-दिशात्मक मानचित्रण। बस @ जॉइनकॉलम का उपयोग करें



कंपनी तालिका में का ।

@Entity
public class Company {

@OneToMany(cascade = CascadeType.ALL , fetch = FetchType.LAZY)
@JoinColumn(name="courseId")
private List<Branch> branches;
...
}

यह कहता है कि शाखाओं की तालिका में विदेशी कुंजी "कोर्सआईड" मैपिंग के आधार पर, मुझे सभी शाखाओं की सूची प्राप्त करें। नोट: आप इस मामले में शाखा से कंपनी नहीं ला सकते, केवल कंपनी से शाखा तक यूनि-दिशात्मक मानचित्रण मौजूद है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.