आप किस स्थिति में JPA @JoinTable एनोटेशन का उपयोग करते हैं?


जवाबों:


351

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तालिका एक "में शामिल होने तालिका" कहा जाता है। जेपीए में इस दूसरे समाधान को लागू करने के लिए आपको @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;
    }

}

यह निम्नलिखित डेटाबेस संरचना बनाएगा:

ईआर डायग्राम 1

@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;

परिणामस्वरूप डेटाबेस बन जाएगा:

ईआर डायग्राम 2

अंत में, यदि आप कई-से-कई एसोसिएशन के लिए एक स्कीमा बनाना चाहते हैं, तो ज्वाइन टेबल का उपयोग करना एकमात्र उपलब्ध समाधान है।


1
पहले दृष्टिकोण का उपयोग करते हुए मेरे पास मेरा प्रोजेक्ट मेरे कार्यों से भरा हुआ है और प्रत्येक टास्क मर्ज से पहले पेरेंट प्रोजेक्ट से भरा हुआ है और काम करता है लेकिन मेरे सभी एंट्रीज़ को मेरे कार्यों की संख्या के आधार पर डुप्लिकेट किया गया है। मेरे डेटाबेस में दो कार्यों के साथ एक परियोजना दो बार सहेजी जाती है। क्यों ?
MaikoID

अद्यतन मेरे डेटाबेस में डुप्लिकेट प्रविष्टियाँ नहीं हैं, हाइबरनेट बाएँ बाहरी जोड़ के साथ चयन कर रहा है और मुझे पता नहीं क्यों ..
MaikoID

2
मेरा मानना ​​है कि @JoinTable/@JoinColumnउसी क्षेत्र के साथ एनोटेट किया जा सकता है mappedBy। तो सही उदाहरण रखते हुए किया जाना चाहिए mappedByमें Project, और ले जाने के @JoinColumnलिए Task.project (या इसके विपरीत)
एड्रियन शुम

2
अच्छा! लेकिन मैं एक और सवाल है: यदि में शामिल होने तालिका Project_Tasksकी जरूरत है nameकी Taskजो तीन कॉलम हो जाता है और साथ ही,: project_id, task_id, task_name, कैसे इस लक्ष्य को हासिल करने के लिए?
मैसर्स

5
मुझे लगता है कि आपको इस त्रुटि को रोकने के लिए अपने दूसरे उपयोग के उदाहरण पर मैप नहीं करना चाहिएCaused by: org.hibernate.AnnotationException: Associations marked as mappedBy must not define database mappings like @JoinTable or @JoinColumn:
कार्तिक एम

14

यह भी उपयोग करने के लिए क्लीनर है @JoinTableजब कई माता-पिता / विभिन्न प्रकार के माता-पिता के साथ बच्चे के संबंधों में एक इकाई बच्चा हो सकता है। Behrang के उदाहरण के साथ पालन करने के लिए, एक कार्य की कल्पना करें परियोजना, व्यक्ति, विभाग, अध्ययन और प्रक्रिया का बच्चा हो सकता है।

क्या taskतालिका में 5 nullableविदेशी कुंजी फ़ील्ड होनी चाहिए ? मुझे नहीं लगता...


14

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

यह OneToMany (आमतौर पर यूनिडायरेक्शनल) संघों के लिए भी उपयोग किया जाता है जब आप कई पक्ष की तालिका में एक विदेशी कुंजी नहीं जोड़ना चाहते हैं और इस तरह इसे एक तरफ से स्वतंत्र रखते हैं।

स्पष्टीकरण और उदाहरण के लिए हाइबरनेट प्रलेखन में @JoinTable के लिए खोजें ।


4

यह आपको कई से कई संबंधों को संभालने देता है। उदाहरण:

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 |
|_________|_________|
|         |         |
|_________|_________|

1
प्रश्न: क्या होगा यदि मेरे पास पहले से ही यह अतिरिक्त तालिका है? JoinTable अभ्यस्त एक अस्तित्व को अधिलेखित कर देगा?
TheWandererr

@ TheWandererr क्या आपको अपने प्रश्न का उत्तर पता चला? मेरे पास पहले से ही एक
जॉइनिंग

मेरे मामले में यह स्वयं की साइड टेबल में एक निरर्थक कॉलम बना रहा है। उदाहरण के लिए। POST_ID POST में। क्या आप सुझाव दे सकते हैं कि ऐसा क्यों हो रहा है?
एसपीएस

0

@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विशेषता।

ध्यान दें कि @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 </ कोड> जेपीए एसोसिएशन डेटाबेस टेबल

जैसा कि पहले ही समझाया गया है, यूनिडायरेक्शनल @OneToManyजेपीए मैपिंग कई-से-कई एसोसिएशन की तरह व्यवहार करता है।

लिंक तालिका को अनुकूलित करने के लिए, आप @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पक्ष का उपयोग कर बेहतर हैं । की जाँच करें इस लेख में इस विषय के बारे में अधिक जानकारी के लिए।

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