2010-08-01 11 views
8

मेरे पास इकाई ए है जिसमें एक बी इकाई है, और बी है-ए ए @OneToOne बिडरेक्शनल एसोसिएशन के साथ है।हाइबरनेट एक @OneToOne बिडरेक्शनल एसोसिएशन उत्सुक लोड के लिए दो प्रश्न क्यों करता है?

अब

, जब मैं एक रिकॉर्ड findall,, कुछ इस तरह बी पर शामिल होने के एक छोड़ दिया बाहरी के साथ दो प्रश्न करने होंगे हाइबरनेट:

select a.id, a.id_b, a.field1, b.id, b.field1 from A as a, B as b left outer join b ON b.id=a.id_b; 
select a.id, a.id_b, a.field1, b.id, b.field1 from A as a, B as b left outer join b ON b.id=a.id_b WHERE b.id=? 

पहले क्वेरी लोड ए और बी के खेतों और यह ठीक है, लेकिन क्यों प्रदर्शन पुनः लोड करने के लिए दूसरी क्वेरी? मुझे लगता है कि यह क्वेरी बी में ए सामग्री को लोड करती है, लेकिन यह ए obviusly ए है जिसमें बी है ... तो यह पहले से ही पहले क्वेरी के साथ लोड किया गया है, सच नहीं है?

- संपादित करें -

इकाई एक:

@Entity 
public class A implements Serializable{ 
    // id and other ecc ecc 
    @OneToOne 
    @JoinColumn(name="id_b") 
    B b; 
} 

इकाई बी:

@Entity 
public class B implements Serializable{ 
    // id and other ecc ecc 
    @OneToOne(mappedBy="b") 
    A a; 
} 

यह स्थिति है, और एक की जरूरत है दो प्रश्नों पर एक findAll है .. । क्यूं कर?

उत्तर

6

ब्लो, अगर ए और बी शेयर एक ही प्राथमिक कुंजी स्तंभ जहां दोनों संस्थाओं का उपयोग करके शामिल हो गए हैं उनके प्राथमिक कुंजी, आप के बजाय

@Entity 
public class A implements Serializable { 

    private MutableInt id = new MutableInt(); 

    private B b; 

    public void setIdAsMutableInt(MutableInt id) { 
     this.id = id; 
    } 

    @Id 
    @GeneratedValue 
    public Integer getId() { 
     return id.intValue(); 
    } 

    public void setId(Integer id) { 
     this.id.setValue(id); 
    } 

    /** 
     * Any ToOne annotation, such as @OneToOne and @ManyToOne, is EARGELY loaded, by default 
     */ 
    @OneToOne(fetch=FetchType.LAZY) 
    @PrimaryKeyJoinColumn 
    @Cascade(CascadeType.SAVE_UPDATE) 
    public B getB() { 
     return b; 
    } 

    public void setB(B b) { 
     b.setIdAsMutableInt(id); 

     this.b = b; 
    } 

} 

@PrimaryKeyJoinColumn का उपयोग करना चाहिए और बी सूचना आप करते हैं mappedBy विशेषता की वजह से @PrimaryKeyJoinColumn की जरूरत नहीं

@Entity 
public class B implements Serializable { 

    private MutableInt id = new MutableInt(); 

    private A a; 

    public void setIdAsMutableInt(MutableInt id) { 
     this.id = id; 
    } 

    @Id 
    public Integer getId() { 
     return id.intValue(); 
    } 

    public void setId(Integer id) { 
     this.id.setValue(id); 
    } 

    @OneToOne(fetch=FetchType.LAZY) 
    @PrimaryKeyJoinColumn 
    public A getA() { 
     return a; 
    } 

    public void setA(A a) { 
     this.a = a; 
    } 

} 

आइए टेस्ट पूर्णांक के बजाय (आप अगर आप चाहते हैं का परीक्षण कर सकते हैं)

A a = new A(); 
B b = new B(); 

a.setB(b); 

/** 
    * b property will be saved because Cascade.SAVE_UPDATE 
    */ 
Serializable id = session.save(a); 

b = (B) session 
     .createQuery("from B b left join fetch b.a where b.id = :id") 
     .setParameter("id", id) 
     .list() 
     .get(0); 

Assert.assertEquals(b.getId(), b.getA().getId()); 

सूचना मैं एक MutableInt क्षेत्र (एक पूर्णांक संपत्ति के द्वारा समझाया) का उपयोग करें क्योंकि पूर्णांक एक तरह से दोनों एक और के रूप में एक अपरिवर्तनीय प्रकार है बी शेयर वही सौंपा आईडी

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

इस प्रकार है
@Entity 
public class A implements Serializable { 

    private Integer id; 

    private B b; 

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

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

    /** 
     * mappedBy="a" means: Look at "a" field/property at B Entity. If it has any assigned value, join us Through B_ID foreign key column 
     */ 
    @OneToOne(fetch=FetchType.LAZY, mappedBy="a") 
    /** 
     * Table A has a foreign key column called "B_ID" 
     */ 
    @JoinColumn(name="B_ID") 
    @Cascade(CascadeType.SAVE_UPDATE) 
    public B getB() { 
     return b; 
    } 

    public void setB(B b) { 
     this.b = b; 
    } 

} 

और बी

@Entity 
public class B implements Serializable { 

    private Integer id; 

    private A a; 

    public void setIdAsMutableInt(MutableInt id) { 
     this.id = id; 
    } 

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

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

    @OneToOne(fetch=FetchType.LAZY) 
    public A getA() { 
     return a; 
    } 

    public void setA(A a) { 
     this.a = a; 
    } 

} 

A a = new A(); 
B b = new B(); 

/** 
    * Set up both sides 
    * Or use some kind of add convenience method 
    */ 
a.setB(b); 
b.setA(a); 

/** 
    * b property will be saved because Cascade.SAVE_UPDATE 
    */ 
Serializable id = session.save(a); 

b = (B) session 
     .createQuery("from B b left join fetch b.a where b.id = :id") 
     .setParameter("id", id) 
     .list() 
     .get(0); 

परीक्षण करने के लिए स्वामी की ओर बी का उपयोग करके, आप दो का चयन बयान यह तब होता है मिल जाएगा क्योंकि बी तालिका किसी भी विदेशी कुंजी शामिल नहीं है कॉलम जो तालिका ए को इंगित करता है लेकिन

का उपयोग करके

"एक से एक बाएं में शामिल होने लाने अब जहां a.id =: आईडी"

आप सिर्फ एक का चयन स्टेटमेंट मिलेगा क्योंकि एक जानता है कि कैसे अपने B_ID विदेशी कुंजी स्तंभ

का उपयोग करके अपने में शामिल हो गए बी प्राप्त करने के लिए
+0

धन्यवाद !! बहुत संपूर्ण! – blow

0

आपका मानचित्रण बिल्कुल कैसा दिखता है?

अपने A और B वर्गों को सही ढंग से hashCode() और equals() लागू तो हाइबरनेट बता सकता है कि कि A उदाहरण B द्वारा की ओर इशारा किया पहले A का एक ही उदाहरण है?

लगता है जैसे आप एक द्वि-दिशात्मक एक-से-एक मैपिंग मॉडल करने की कोशिश कर रहे हैं - इसे पूरा करने के लिए अनुशंसित विधियों को देखने के लिए the section in the manual on this पर एक नज़र डालें।

+0

मैंने अपनी पोस्ट संपादित की। हां मेरे पास समान रूप से आईडी पर आधारित बराबर और हैशकोड का एक बहुत ही सरल कार्यान्वयन है। मेरे सभी entites इस कार्यान्वयन के साथ एक सार तत्व प्रदान करता है। – blow

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