2010-08-03 31 views
68

का एक से अधिक संबंध कैसे हो सकता है वहां एक इकाई वर्ग "ए" है। कक्षा ए में एक ही प्रकार के बच्चे "ए" हो सकते हैं। इसके अलावा "ए" को अपने माता-पिता को पकड़ना चाहिए यदि यह बच्चा है।जेपीए: एक ही इकाई प्रकार

क्या यह संभव है? यदि ऐसा है तो मैं इकाई वर्ग में संबंधों को कैसे मैप करना चाहिए? ["ए" में एक आईडी कॉलम है।]

उत्तर

128

हां, यह संभव है। यह मानक बिडरेक्शनल @ManyToOne/@OneToMany संबंध का एक विशेष मामला है। यह विशेष है क्योंकि रिश्ते के प्रत्येक छोर पर इकाई समान है। सामान्य मामला JPA 2.0 spec की धारा 2.10.2 में विस्तृत है।

यहां एक काम किया गया उदाहरण है। सबसे पहले, इकाई वर्ग A:

@Entity 
public class A implements Serializable { 

    @Id 
    @GeneratedValue(strategy=GenerationType.AUTO) 
    private Long id; 
    @ManyToOne 
    private A parent; 
    @OneToMany(mappedBy="parent") 
    private Collection<A> children; 

    // Getters, Setters, serialVersionUID, etc... 
} 

यहाँ एक किसी न किसी main() विधि कि इस तरह के तीन संस्थाओं बनी रहती है:

public static void main(String[] args) { 

    EntityManager em = ... // from EntityManagerFactory, injection, etc. 

    em.getTransaction().begin(); 

    A parent = new A(); 
    A son  = new A(); 
    A daughter = new A(); 

    son.setParent(parent); 
    daughter.setParent(parent); 
    parent.setChildren(Arrays.asList(son, daughter)); 

    em.persist(parent); 
    em.persist(son); 
    em.persist(daughter); 

    em.getTransaction().commit(); 
} 

इस मामले में, सभी तीन इकाई उदाहरणों कायम किया जाना चाहिए इससे पहले कि लेन-देन के लिए प्रतिबद्ध। यदि मैं अभिभावक-बाल संबंधों के ग्राफ में इकाइयों में से एक को जारी रखने में विफल रहता हूं, तो commit() पर एक अपवाद फेंक दिया जाता है। Eclipselink पर, यह एक RollbackException असंगतता का विवरण है।

यह व्यवहार A के @OneToMany और @ManyToOne एनोटेशन पर विशेषता के माध्यम से कॉन्फ़िगर करने योग्य है। उदाहरण के लिए, यदि मैंने उन दोनों टिप्पणियों पर cascade=CascadeType.ALL सेट किया है, तो मैं सुरक्षित रूप से इकाइयों में से एक को कायम रख सकता हूं और दूसरों को अनदेखा कर सकता हूं। मान लें कि मैंने अपने लेनदेन में parent जारी रखा। जेपीए कार्यान्वयन parent की children संपत्ति को पार करता है क्योंकि इसे CascadeType.ALL के साथ चिह्नित किया गया है। जेपीए कार्यान्वयन में son और daughter मिलते हैं। यह तब मेरी ओर से दोनों बच्चों को बनी रहती है, भले ही मैंने स्पष्ट रूप से अनुरोध नहीं किया था।

एक और नोट। द्विपक्षीय संबंधों के दोनों पक्षों को अद्यतन करना हमेशा प्रोग्रामर की ज़िम्मेदारी है। दूसरे शब्दों में, जब भी मैं किसी बच्चे को किसी बच्चे को जोड़ता हूं, तो मुझे उसके अनुसार बच्चे की मूल संपत्ति को अपडेट करना होगा। एक द्विपक्षीय संबंध के केवल एक पक्ष को अद्यतन करना जेपीए के तहत एक त्रुटि है। हमेशा रिश्ते के दोनों तरफ अद्यतन करें। यह जेपीए 2.0 कल्पना की पेज 42 पर स्पष्ट लिखा है:

ध्यान दें कि यह अनुप्रयोग है कि क्रम की निरंतरता को बनाए रखने के लिए जिम्मेदारी भालू है रिश्तों-उदाहरण के लिए, बीमा है कि "एक" और "कई के लिए "एक द्विपक्षीय संबंध के पक्ष एक दूसरे के साथ संगत होते हैं जब एप्लिकेशन रनटाइम पर संबंध अपडेट करता है।

+0

विस्तृत स्पष्टीकरण के लिए बहुत बहुत धन्यवाद!उदाहरण बिंदु पर है और पहले भाग में काम किया। – sanjayav

+0

@sunnyj मदद करने के लिए खुशी हुई। अपनी परियोजना के साथ शुभकामनाएं। –

+0

उप-श्रेणियों वाली श्रेणी इकाई बनाने के पहले यह इस मुद्दे से मुलाकात की। ये उपयोगी है! –

5

मेरे लिए यह चाल कई से अधिक रिश्तों का उपयोग करना था। मान लीजिए कि आपकी इकाई ए एक ऐसा प्रभाग है जिसमें सब-डिवीजन हो सकते हैं। तब (अप्रासंगिक विवरण लंघन):

:

@Entity 
@Table(name = "DIVISION") 
@EntityListeners({ HierarchyListener.class }) 
public class Division implements IHierarchyElement { 

    private Long id; 

    @Id 
    @Column(name = "DIV_ID") 
    public Long getId() { 
     return id; 
    } 
    ... 
    private Division parent; 
    private List<Division> subDivisions = new ArrayList<Division>(); 
    ... 
    @ManyToOne 
    @JoinColumn(name = "DIV_PARENT_ID") 
    public Division getParent() { 
     return parent; 
    } 

    @ManyToMany 
    @JoinTable(name = "DIVISION", joinColumns = { @JoinColumn(name = "DIV_PARENT_ID") }, inverseJoinColumns = { @JoinColumn(name = "DIV_ID") }) 
    public List<Division> getSubDivisions() { 
     return subDivisions; 
    } 
... 
} 

जब से मैं सौपानिक संरचना और जेपीए के आसपास कुछ व्यापक व्यापार तर्क था (संबंधपरक मॉडल के आधार पर) यह समर्थन करने के लिए मैं इंटरफ़ेस IHierarchyElement और इकाई श्रोता HierarchyListener शुरू की बहुत कमजोर है

public interface IHierarchyElement { 

    public String getNodeId(); 

    public IHierarchyElement getParent(); 

    public Short getLevel(); 

    public void setLevel(Short level); 

    public IHierarchyElement getTop(); 

    public void setTop(IHierarchyElement top); 

    public String getTreePath(); 

    public void setTreePath(String theTreePath); 
} 


public class HierarchyListener { 

    @PrePersist 
    @PreUpdate 
    public void setHierarchyAttributes(IHierarchyElement entity) { 
     final IHierarchyElement parent = entity.getParent(); 

     // set level 
     if (parent == null) { 
      entity.setLevel((short) 0); 
     } else { 
      if (parent.getLevel() == null) { 
       throw new PersistenceException("Parent entity must have level defined"); 
      } 
      if (parent.getLevel() == Short.MAX_VALUE) { 
       throw new PersistenceException("Maximum number of hierarchy levels reached - please restrict use of parent/level relationship for " 
         + entity.getClass()); 
      } 
      entity.setLevel(Short.valueOf((short) (parent.getLevel().intValue() + 1))); 
     } 

     // set top 
     if (parent == null) { 
      entity.setTop(entity); 
     } else { 
      if (parent.getTop() == null) { 
       throw new PersistenceException("Parent entity must have top defined"); 
      } 
      entity.setTop(parent.getTop()); 
     } 

     // set tree path 
     try { 
      if (parent != null) { 
       String parentTreePath = StringUtils.isNotBlank(parent.getTreePath()) ? parent.getTreePath() : ""; 
       entity.setTreePath(parentTreePath + parent.getNodeId() + "."); 
      } else { 
       entity.setTreePath(null); 
      } 
     } catch (UnsupportedOperationException uoe) { 
      LOGGER.warn(uoe); 
     } 
    } 

} 
+1

स्वयं-संदर्भ गुणों के साथ @ManyToMany (...) के बजाय सरल @OneToMany (mappedBy = "DIV_PARENT_ID") का उपयोग क्यों न करें? तालिका और कॉलम नामों को रीटिप करने जैसे डीआरवाई का उल्लंघन होता है। शायद इसके लिए एक कारण है, लेकिन मुझे यह नहीं दिख रहा है। इसके अलावा, EntityListener उदाहरण साफ है लेकिन गैर पोर्टेबल है, मानते हैं कि 'टॉप' एक रिश्ते है। जेपीए 2.0 स्पेक, एंटिटी श्रोताओं और कॉलबैक विधियों का पृष्ठ 9 3: "सामान्य रूप से, एक पोर्टेबल एप्लिकेशन की जीवन चक्र विधि को EntityManager या क्वेरी ऑपरेशंस का आह्वान नहीं करना चाहिए, अन्य इकाई उदाहरणों तक पहुंच या रिश्तों को संशोधित नहीं करना चाहिए"। सही? अगर मैं बंद हूं तो मुझे बताएं। –

+0

मेरा समाधान जेपीए 1.0 का उपयोग कर 3 साल पुराना है। मैंने इसे उत्पादन कोड से अपरिवर्तित अनुकूलित किया। मुझे यकीन है कि मैं कुछ कॉलम नाम निकाल सकता हूं लेकिन यह मुद्दा नहीं था। आपका जवाब यह बिल्कुल सही और सरल है, यह सुनिश्चित नहीं है कि मैंने कई लोगों को क्यों उपयोग किया - लेकिन यह काम करता है और मुझे पूरा भरोसा है कि किसी कारण से अधिक जटिल समाधान था। हालांकि, मुझे अब इसे फिर से देखना होगा। – topchef

+0

हां, शीर्ष एक आत्म-संदर्भ है, इसलिए एक रिश्ता है। कड़ाई से बोलते हुए, मैं इसे संशोधित नहीं करता - बस आरंभ करें। इसके अलावा, यह एकजुट है इसलिए दूसरी तरफ कोई निर्भरता नहीं है, यह स्वयं के अलावा अन्य संस्थाओं का संदर्भ नहीं देती है। आपके उद्धरण के अनुसार "सामान्य में" जिसका अर्थ है कि यह सख्त परिभाषा नहीं है। मेरा मानना ​​है कि इस मामले में यदि कोई हो तो बहुत कम पोर्टेबिलिटी जोखिम है। – topchef

संबंधित मुद्दे