2014-07-03 3 views
6

जेपीए 1 (हाइबरनेट-कोर संस्करण 3.3.0.एसपी 1 और हाइबरनेट-इकाई प्रबंधक संस्करण 3.4.0.GA) के साथ काम करना: मेरे पास नीचे दी गई परिभाषाओं के समान कुछ संस्थाएं हैं, जहां चाइल्डऑन और चाइल्डटो से विस्तारित है पिता इकाईजेपीए विरासत मुद्दा

@Entity 
@Table(name = "TABLE_FATHER") 
@Inheritance(strategy = InheritanceType.JOINED) 
@DiscriminatorColumn(discriminatorType = DiscriminatorType.INTEGER, name = Father.C_ID_CTG) 
public class Father { 

@Id 
@GeneratedValue(strategy = GenerationType.AUTO, generator = "sq") 
@Column(name = "ID_PK", nullable = false) 
@BusinessId 
private Long id; 
... 
} 

@Entity 
@Table(name = "TABLE_CHILD_ONE") 
@Inheritance(strategy = InheritanceType.JOINED) 
@DiscriminatorValue(Categories.ID_CTG_ONE) 
public class ChildOne extends Father { 
    ... 
} 

@Entity 
@Table(name = "TABLE_CHILD_TWO") 
@Inheritance(strategy = InheritanceType.JOINED) 
@DiscriminatorValue(Categories.ID_CTG_TWO) 
public class ChildTwo extends Element { 
    ... 
} 

मान लें कि मेरे पास एक इकाई है जिसमें पिता तत्व है, और दूसरा पिता तत्वों का संग्रह है। दोनों मामलों में, बच्चों की संस्थाओं को जाना चाहिए।

@Entity 
@Table(name = "TABLE_ONE") 
public class OneTable { 

@JoinColumn(name = "ID_PK", referencedColumnName = "ID_PK", nullable = false) 
@ManyToOne(optional = false, fetch = FetchType.LAZY) 
private Father element; 
    ... 
} 

@Entity 
@Table(name = "TABLE_ANOTHER") 
public class Another { 

@Fetch(FetchMode.JOIN) 
@OneToMany(cascade = CascadeType.ALL, mappedBy = "id", fetch = FetchType.LAZY) 
private Collection<Father> elementCollection; 

    ... 
} 

मैं हमेशा बच्चों तत्वों प्राप्त करने के लिए उम्मीद कर रहा हूँ, लेकिन जब मैं तत्व getElement() पिता तत्व वापस आती है और दूसरी तरफ, जब मैं संग्रह getElementCollection() बच्चों तत्वों आ रहे हैं मिलता है मिलता है।

जाहिर है, @JoinColumn इस व्यवहार का कारण है, पिता की मेज के साथ जुड़ना और बच्चों के तत्वों को भूलना। संग्रह अपेक्षित के रूप में काम कर रहा है।

मैं getElement() कॉल के साथ बच्चों के तत्व को कैसे प्राप्त कर सकता हूं? कोई विचार या कामकाज? अग्रिम धन्यवाद।

उत्तर

2

समस्या @JoinColumn के कारण नहीं है। कारण आलसी लोड हो रहा है। मैं आपकी समस्या को सरल उदाहरण में इंगित करने का प्रबंधन करता हूं। पिता से माता-पिता से सम्मेलन बदलने के लिए मुझे माफ़ कर दो।

नीचे दिए गए उदाहरण में, अनियमित तत्व jpa.inheritance.issue.Parent_$$_javassist_1 का प्रकार है। यह एक हाइबरनेट प्रॉक्सी है - गतिशील रूप से अभिभावक का उप-वर्ग बनाया गया है। आप हाइबरनेट प्रोप्रायटरी एपीआई getHibernateLazyInitializer().getImplementation() का आह्वान करके इसे "असम्पीडित" कर सकते हैं।

elementCollection का संग्रह भी आलसी प्रारंभिक है। संग्रह का प्रकार org.hibernate.collection.PersistentBag है जिसे पहली पहुंच के समय सही डेटा के साथ initilized किया जा रहा है। संग्रह एक ही समय में शुरू किया गया है। कृपया परीक्षण देखें जो सफलतापूर्वक हर्बेनेट (3.3.0.एसपी/3.4.0.जीए) के अपने सटीक संस्करण के साथ हरा पारित हुआ।

@Test 
    public void test() { 
     Child c = new Child(); 
     em.persist(c); 

     Another a = new Another(); 
     a.setElement(c); 
     Collection<Parent> col = new ArrayList<Parent>(); 
     col.add(c); 
     a.setElementCollection(col); 
     em.persist(a); 
     c.setAnother(a); 

     long idx = a.getId(); 
     tx.commit(); 

     // I'm cleaning the cache to be sure that call to a.getElement() will return proxy. 
     em.clear(); 
     tx = em.getTransaction(); 
     tx.begin(); 

     a = em.find(Another.class, idx); 
     Assert.assertNotNull(a); 
     Parent p = a.getElement(); 
     // At this point p is a type of jpa.inheritance.issue.Parent_$$_javassist_1 

     Assert.assertTrue(p instanceof Parent); 
     Assert.assertFalse(p instanceof Child); 

     // At this point a.elements is a not initialized (empty) collection of type org.hibernate.collection.PersistentBag 
     // When we access this collection for the first time, records are read from the database 
     Assert.assertEquals(1, a.getElementCollection().size()); 

     if (p instanceof HibernateProxy) { 
      p = 
        (Parent) ((HibernateProxy) p).getHibernateLazyInitializer() 
          .getImplementation(); 
     } 

     // At this point p is a type of jpa.inheritance.issue.Child 
     Assert.assertTrue(p instanceof Child); 
    } 

    @Entity 
    public class Another { 

     @JoinColumn(name = "element_id", referencedColumnName = "id", nullable = false) 
     @ManyToOne(fetch=FetchType.LAZY) 
     private Parent element; 
     public Parent getElement() { 
      return element; 
     } 

     public void setElement(Parent element) { 
      this.element = element; 
     } 

     @OneToMany(cascade = CascadeType.ALL, mappedBy = "another", fetch = FetchType.LAZY) 
     public Collection<Parent> elements; 

     public Collection<Parent> getElementCollection() { 
      return elements; 
     } 

     public void setElementCollection(Collection<Parent> elementCollection) { 
      this.elements = elementCollection; 
     } 

     // @Id ... 
    } 

    @Entity 
    @Inheritance(strategy = InheritanceType.JOINED) 
    public class Parent { 
     @ManyToOne 
     private Another another; 

     public Another getAnother() { 
      return another; 
     } 

     public void setAnother(Another another) { 
      this.another = another; 
     } 

     // @Id ... 
    } 

    @Entity 
    public class Child extends Parent {   
    } 

आप @DiscriminatorColumn है और न ही @DiscriminatorValue की जरूरत नहीं, क्योंकि उन एनोटेशन एक ही सहारा प्रकार निर्धारित करने के रूप में InheritanceType.SINGLE_TABLE साथ की जरूरत है है। InheritanceType.JOINED के साथ हाइबरनेट एक ही आईडी के साथ दोनों (अभिभावक और बाल) तालिकाओं में एक रिकॉर्ड है या नहीं, यह जांच कर बहुलक प्रकार निर्धारित करने में सक्षम है। आप हाइबरनेट लॉगिंग चालू कर सकते हैं यह देखने के लिए कि प्रकार किस प्रकार दिखने के लिए क्वेरी को दिखाना है। यह इस तरह काम करता है:

select 
    another0_.id as id0_1_, 
    another0_.element_id as element2_0_1_, 
    parent1_.id as id1_0_, 
    parent1_1_.name as name2_0_, 
    case 
     when parent1_1_.id is not null then 1 
     when parent1_.id is not null then 0 
     else -1 
    end as clazz_0_ 
from 
    Another another0_ 
inner join 
    Parent parent1_ 
     on another0_.element_id=parent1_.id 
left outer join 
    Child parent1_1_ 
     on parent1_.id=parent1_1_.id 
where 
    another0_.id=? 
+0

अच्छा बिंदु। मुझे कुछ चीजों को आज़माएं और मैं आपको बता दूंगा ... – elcadro

+0

आपके उत्तर के बारे में कुछ ही नोट्स ... जहां तक ​​मुझे पता है कि spec को जॉइनेड विरासत को लागू करने के लिए भेदभाव कॉलम का उपयोग करने के लिए कार्यान्वयन की आवश्यकता नहीं है, हालांकि, धारणा यह है कि यदि @DiscriminatorColumn निर्दिष्ट किया गया है तो इसका उपयोग किया जाएगा ... दूसरी तरफ, आपका समाधान वास्तव में काम करता है, फिर भी कुछ संदेह हैं। यह जानकर कि आलसी प्रॉक्सी देता है, क्यों कई लोग एक माता-पिता को प्रॉक्सी वापस भेजते हैं (jpa.inheritance.issue.Parent _ $$ _ javassist_1), और वनटॉनी संग्रह बच्चों प्रॉक्सी (jpa.inheritance.issue.ChildOne _ $$ _ javassist_1) ??? – elcadro

+0

असली दुनिया में 'getElement()' कॉल का सटीक वापसी प्रकार निर्धारक नहीं है।कारण अगर ऑब्जेक्ट 1 या 2 स्तर के कैश में पाया जाता है तो यह 'चाइल्ड' टाइप करेगा। यही कारण है कि मैं विशिष्ट व्यवहार को इंगित करने के लिए मध्य में 'em.clean()' को कॉल करता हूं। यही कारण है कि यह प्रकार अभिभावक-बच्चे पदानुक्रम के साथ स्थिति में नास्तिक होने के लिए सबसे अच्छा है है। यदि आप वास्तव में उत्सुक करने के लिए एक सही प्रकार आप "unproxy" के रूप में मैं प्रस्तावित कर सकते हैं या बेहतर परिवर्तन FetchType जरूरत है (के रूप में "unproxying" वैसे भी संबंध लोड)। – zbig

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