समस्येचे वर्णन

आम्ही वर म्हटल्याप्रमाणे, LazyCollectionOption.EXTRA भाष्यात समस्या आहे - ती प्रत्येक ऑब्जेक्टसाठी डेटाबेसला स्वतंत्र विनंती करते. आम्ही हायबरनेटला कसे तरी समजावून सांगणे आवश्यक आहे की आम्हाला आमच्या मूळ वस्तूंसाठी सर्व चाइल्ड ऑब्जेक्ट्स त्वरित लोड करायचे आहेत.

हायबरनेटच्या विकसकांनी या समस्येवर उपाय शोधून काढला आहे, HQL मधील जॉईन फेच ऑपरेटर .

HQL क्वेरी उदाहरण:

select distinct task from Task t left join fetch t.employee order by t.deadline

या क्वेरीमध्ये, सर्व काही एकाच वेळी सोपे आणि जटिल आहे. चला तुकड्या-तुकड्याने तयार करण्याचा प्रयत्न करूया.

पर्याय 1

आम्हाला सर्व ऑब्जेक्ट्स डाउनलोड करायचे आहेतकार्य, अंतिम मुदतीनुसार क्रमवारी लावलेली. ती विनंती कशी दिसेल ते येथे आहे:

select task from Task t order by t.deadline

सर्व काही स्पष्ट असताना. पण फील्डकर्मचारीटास्क क्लासमध्ये एक्स्ट्रा एनोटेशनसह भाष्य केलेल्या कर्मचाऱ्यांचा संग्रह असेल . आणि या संग्रहातील वस्तू लोड केल्या जाणार नाहीत.

पर्याय २

एखाद्या ऑब्जेक्टसाठी चाइल्ड ऑब्जेक्ट लोड करण्यासाठी हायबरनेटला सक्ती कराकार्य.

select task from Task t join fetch t.employee order by t.deadline

मदतीसह, आम्ही आमच्या क्वेरीमध्ये कार्य आणि कर्मचारी घटकांना स्पष्टपणे बांधतो. हायबरनेटला हे आधीच माहित आहे कारण आम्ही या फील्डवर @ManyToMany भाष्ये वापरतो.

परंतु आम्हाला जॉईन फेच मिळवण्यासाठी फेच स्टेटमेंटसह ते पूर्ण करण्यासाठी जॉईन स्टेटमेंट आवश्यक आहे . अशा प्रकारे आम्ही हायबरनेटला सांगतो की Task.employee कलेक्शनमधील ऑब्जेक्ट्स डेटाबेसमधून लोड करणे आवश्यक आहे जेव्हा आमची विनंती कार्यान्वित केली जाते.

पर्याय 3

मागील सोल्यूशनमध्ये काही बग आहेत. प्रथम, जॉईन वापरल्यानंतर, SQL आम्हाला वस्तू परत करणार नाहीकार्य, ज्यांच्याशी कर्मचारी तक्त्यामध्ये कोणतीही वस्तू संबंधित नाही. आतील जॉईन हे नेमके कसे कार्य करते .

त्यामुळे आम्हाला डाव्या ऑपरेटरसह आमची जोडणी वाढवायची आहे आणि ती डाव्या जोडणीमध्ये बदलायची आहे . उदाहरण:

select task from Task t left join fetch t.employee order by t.deadline

पर्याय 4

पण एवढेच नाही. तुमच्‍या कोडमध्‍ये घटकांमध्‍ये अनेक-टू-मे संबंध असल्‍यास, क्‍वेरी परिणामांमध्‍ये डुप्‍लिकेट असतील. तीच वस्तुकार्यवेगवेगळ्या कर्मचार्‍यांवर (कर्मचारी वस्तू) आढळू शकतात.

त्यामुळे डुप्लिकेट टास्क ऑब्जेक्टपासून मुक्त होण्यासाठी तुम्हाला सिलेक्ट शब्दानंतर वेगळा कीवर्ड जोडणे आवश्यक आहे.

select distinct task from Task t left join fetch t.employee order by t.deadline

अशाप्रकारे 4 चरणांमध्ये आम्ही विनंतीवर आलो ज्याने आम्ही सुरुवात केली. बरं, जावा कोड अपेक्षित दिसेल:

String hql = " select distinct task from Task t left join fetch t.employee order by t.deadline";
Query<Task> query = session.createQuery( hql, Task.class);
return query.list();

सामील व्हा मर्यादा आणा

कुणीच परिपूर्ण नाही. FETCH स्टेटमेंटमध्ये देखील सामील व्हा. त्याला काही मर्यादा आहेत. आणि पहिली setMaxResults() आणि setFirstResult() पद्धती वापरत आहे .

जॉइन फेच स्टेटमेंटसाठी, आमचे हायबरनेट एक अतिशय क्लिष्ट क्वेरी तयार करेल ज्यामध्ये आम्ही तीन टेबल्स एकामध्ये एकत्र करतो: कर्मचारी, कार्य आणि कर्मचारी_टास्क. खरं तर, ही कर्मचारी किंवा कार्यांसाठी विनंती नाही, परंतु सर्व ज्ञात कर्मचारी-टास्क जोड्यांसाठी आहे.

आणि एसक्यूएल त्याची मर्यादा आणि ऑफसेट विधाने कर्मचारी-टास्क जोड्यांच्या नेमक्या क्वेरीवर लागू करू शकते. त्याच वेळी, HQL क्वेरीवरून हे स्पष्टपणे दिसून येते की आम्हाला अचूक कार्ये (टास्क) मिळवायची आहेत आणि जर आम्ही आमचे FirstResult आणि MaxResult पॅरामीटर्सचे पुनर्वितरण केले, तर त्यांनी विशेषतः Task ऑब्जेक्ट्सचा संदर्भ घ्यावा.

जर तुम्ही असा कोड लिहिला तर:

String hql = " select distinct task from Task t left join fetch t.employee order by t.deadline";
Query<Task> query = session.createQuery( hql, Task.class);
       	    query.setFirstResult(0);
        	   query.setMaxResults(1);
return query.list();

नंतर हायबरनेट फर्स्ट रिझल्ट आणि मॅक्स रिझल्टला SQL क्वेरीच्या OFFSET आणि LIMIT पॅरामीटर्समध्ये योग्यरित्या रूपांतरित करू शकणार नाही.

त्याऐवजी, ते तीन गोष्टी करेल:

  • SQL क्वेरी टेबलमधील सर्व डेटा निवडेल आणि हायबरनेटमध्ये परत करेल
  • हायबरनेट त्याच्या मेमरीमध्ये आवश्यक रेकॉर्ड निवडेल आणि ते तुम्हाला परत करेल
  • हायबरनेट चेतावणी जारी करेल

चेतावणी अशी असेल:

WARN [org.hibernate.hql.internal.ast.QueryTranslatorImpl] HHH000104: 
firstResult/maxResults specified with collection fetch; applying in memory!