2015-09-28 5 views
7

मेरे पास एक अजीब समस्या है जहां हाइबरनेट अपेक्षाकृत इकाई प्रकार को कई से एक रिलायंसशिप में नहीं बनाता है।रिश्ते में गलत इकाई उप प्रकार का निर्माण करने के लिए हाइबरनेट

@Entity 
@Table(name = "A") 
@Inheritance(strategy = InheritanceType.SINGLE_TABLE) 
@DiscriminatorColumn(name = "DISCRIMINATOR", discriminatorType = DiscriminatorType.STRING, length = 1) 
public abstract class A { 

    @Id 
    ... 
    public Long getId() { ... } 
    ... 
} 

@Entity 
@DiscriminatorValue("1") 
public class A1 extends A { 
    ... 
} 

@Entity 
@DiscriminatorValue("2") 
public class A2 extends A { 
    ... 
} 


@Entity 
@Table(name = "B") 
@Inheritance(strategy = InheritanceType.SINGLE_TABLE) 
@DiscriminatorColumn(name = "DISCRIMINATOR", discriminatorType = DiscriminatorType.STRING, length = 1) 
public abstract class B<AClass extends A> { 

    protected AClass a; 

    @Id 
    ... 
    public Long getId() { ... } 
    ... 

    public abstract AClass getA(); 
    public void setA(AClass a) { ... } 
} 

@Entity 
@DiscriminatorValue("1") 
public class B1 extends B<A1> { 
    ... 

    @Override 
    @ManyToOne(fetch = EAGER) 
    @JoinColumn(name = "A_ID") 
    public A1 getA() { ... } 
} 

@Entity 
@DiscriminatorValue("2") 
public class B2 extends B<A2> { 
    ... 

    @Override 
    @ManyToOne(fetch = EAGER) 
    @JoinColumn(name = "A_ID") 
    public A2 getA() { ... } 
} 

persistence.xml में दोनों संस्थाओं के क्रम

A2 
A1 
B2 
B1 

अब मैं डीबी में A1 के उदाहरण और बी 1 बनाने घोषित किये गए हैं:

हम उपवर्ग पदानुक्रम के साथ निम्नलिखित संस्थाओं (सरलीकृत) है
A1 a1 = new A1(); 
entityManager.persist(a1); 
B1 b1 = new B1(); 
b1.setA(a1); 
entityManager.persist(b1); 

मैं देख सकता हूं कि उदाहरण डीबी में सहेजे गए हैं, प्रत्येक में आईडी 1 है, डिस्क्रिमिनेटर भी 1 है, बी में ए_आईडी भी है 1.

जब मैं अब बी प्राप्त करने के लिए (एक और हाइबरनेट सत्र में) की कोशिश:

org.hibernate.PropertyAccessException: Exception occurred inside getter of B 
Caused by: java.lang.ClassCastException: A2 cannot be cast to A1 
at B1.getA(B1.java:61) 
... 108 more 
डिबगिंग के साथ

मुझे पता चला है कि हाइबरनेट का सही इकाई पैदा कर रही है:

B b = entityManager.find(B.class, 1L); 

मैं अपवाद बी 1 टाइप करें और ए के संबंध के लिए टाइप ए 2 की गलत इकाई बनाता है। persistence.xml में ऑर्डर बदल दिया गया है तो सही प्रकार ए 1 बनाया गया है। ऐसा लगता है कि हाइबरनेट इस मामले में किसी तालिका के डिस्क्रिमिनेटर कॉलम को खाते में नहीं लेता है लेकिन कॉन्फ़िगरेशन में घोषित पहली उपप्रकार बनाता है। इसे कैसे सुधारा जा सकता है? क्या एनोटेशन के साथ कुछ गड़बड़ है?

(मैं भी पहली बार में महाप्रकार बी में अपनी टिप्पणियों के साथ विधि getA() के ठोस कार्यान्वयन किया था, लेकिन यह इसी तरह की समस्याओं की ओर जाता है।)

उत्तर

3

हाइबरनेट 5.0.2 के साथ। फाइनल मैं @ManyToOne(..., targetEntity = A.class) का उपयोग करके अपना उदाहरण काम करने में सक्षम था। मैंने एक साधारण गेटर के साथ public abstract AClass getA(); को भी बदल दिया।

@Entity 
@Table(name = "B") 
@Inheritance(strategy = InheritanceType.SINGLE_TABLE) 
@DiscriminatorColumn(name = "DISCRIMINATOR", discriminatorType = DiscriminatorType.STRING, length = 1) 
public abstract class B<AClass extends A> { 
    private Long id; 
    private AClass a; 

    @Id 
    @GeneratedValue 
    public Long getId() { 
     return id; 
    } 

    public void setId(Long id) { 
     this.id = id; 
    } 

    @ManyToOne(fetch = FetchType.EAGER, targetEntity = A.class) 
    @JoinColumn(name = "A_ID") 
    public AClass getA() { 
     return a; 
    } 

    public void setA(AClass a) { 
     this.a = a; 
    } 
} 
@Entity 
@DiscriminatorValue("1") 
public class B1 extends B<A1> { 
    // no need to override getA() 
} 
@Entity 
@DiscriminatorValue("2") 
public class B2 extends B<A2> { 
    // no need to override getA() 
} 

मैं दस्तावेज में इस व्यवहार के बारे कुछ भी नहीं मिला।तो मैं सिर्फ अपने टिप्पणियों है:

  • targetEntity = A.class बिना हाइबरनेट भी तालिका A की DISCRIMINATOR स्तंभ क्वेरी नहीं था, जब बेसब्री B के साथ A से पंक्तियों को लाते समय, जैसे कि यह पहले से ही A के वास्तविक प्रकार का निर्णय लेने के।
  • जब मैंने targetEntity = A.class जोड़ा, A.DISCRIMINATOR प्रश्नों में दिखाई दिया, और वस्तुओं को A वर्ग के दाएं उप-वर्गों के साथ बनाया गया था।
+0

आपके उत्तर के लिए धन्यवाद। कल मुझे इसका परीक्षण करने का मौका मिला और यह सवाल के परिदृश्य में काम करता है :) – Gandalf

3

आप दोनों B1 में एक ही शामिल होने के स्तंभ (A_ID) का उपयोग कर रहे हैं और B2 सबक्लास।

प्रत्येक उपवर्ग में

उपयोग अलग से एक:

@Entity 
@DiscriminatorValue("1") 
public class B1 extends B<A1> { 
    @Override 
    @ManyToOne(fetch = EAGER) 
    @JoinColumn(name = "A1_ID") 
    public A1 getA() { ... } 
} 

@Entity 
@DiscriminatorValue("2") 
public class B2 extends B<A2> { 
    @Override 
    @ManyToOne(fetch = EAGER) 
    @JoinColumn(name = "A2_ID") 
    public A2 getA() { ... } 
} 

यह मतलब (विभिन्न स्तंभों के साथ एक वैसे भी उपवर्ग के आधार पर प्रत्येक रिकॉर्ड के लिए null हो जाएगा) स्तंभ पुन: उपयोग करने सकता है, यह है कि हाइबरनेट का उपयोग करता है लगता है कॉलम नाम आंतरिक रूप से समान तालिका में कुछ मैपिंग तत्वों की पहचान करने के लिए। यही कारण है कि यह B1 में कई से एक मैपिंग की परिभाषा को अनदेखा करता है और इसके लिए B2 से भी इसका उपयोग करता है (क्योंकि B2 को persistence.xml में B1 से पहले परिभाषित किया गया है)।

+0

अपने जवाब के लिए धन्यवाद Dragan! :) मेरे पास परीक्षण करने का समय नहीं है यदि यह काम करता है क्योंकि दूसरा उत्तर काम करता है और कुछ फायदे हैं: 1. कम कोड। 2. कम डीबी कॉलम 3. हम डीबी कॉलम पर शून्य और विदेशी कुंजी बाधाओं को नहीं रख सकते हैं। – Gandalf

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