2012-07-09 15 views
5

जेपीए के लिए अपेक्षाकृत नया, इसलिए मेरे पास एक प्रकार का वास्तुकला प्रश्न है। चलो कहते हैं कि मैं एक रिश्ते के लिए कई (अर्थात अनेक कर्मचारी एक विभाग के लिए काम करते हैं) के साथ टेबल कर्मचारी और विभाग करते हैं:जेपीए - गणना वर्ग इकाई इकाई वर्ग संपत्ति के रूप में?

EMPLOYEE 
    EMPLOYEE_ID 
    EMPLOYEE_NAME 
    DEPARTMENT_ID 

DEPARTMENT 
    DEPARTMENT_ID 
    DEPARTMENT_NAME 

तो मैं कर्मचारी और विभाग के लिए उचित संस्थाओं को परिभाषित कर सकते हैं, वहाँ कोई समस्या नहीं है। हालांकि, एक दृश्य में मैं इस तरह है कि विभाग के लिए काम करने वाले कर्मचारियों की संख्या, कुछ के साथ विभागों की सूची प्रदर्शित करना चाहते हैं:

SELECT D.DEPARTMENT_NAME, 
     (SELECT COUNT(*) FROM EMPLOYEE E WHERE E.DEPARTMENT_ID = D.DEPARTMENT_ID) NUMBER_OF_EMPLOYEES 
FROM DEPARTMENT D 

मैं सिर्फ यकीन नहीं सही रणनीति इस जेपीए का उपयोग कर पूरा करने के लिए है कि क्या कर रहा हूँ। .. मैं हमेशा विभाग की इकाई के लिए कर्मचारियों की संख्या नहीं लेना चाहता, क्योंकि इसकी आवश्यकता होने पर केवल एक ही दृश्य है।

ऐसा लगता है कि हाइबरनेट का @ फर्मुला एक संभावित दृष्टिकोण होगा, लेकिन afaik यह जेपीए मानक के अनुरूप नहीं है।

उत्तर

4

आप "क्यू" सिंटैक्स का उपयोग करके अपने क्यूएल में कोई ऑब्जेक्ट बना सकते हैं - आपकी कक्षा को केवल एक कन्स्ट्रक्टर की आवश्यकता है जो आपकी क्वेरी द्वारा दिए गए मान लेता है।

उदाहरण के लिए

, DepartmentEmployeeCount की तरह एक वर्ग, एक निर्माता के साथ साथ:

public DepartmentEmployeeCount(String departmentName, Integer employeeCount) 

आप की तरह QL कुछ इस्तेमाल कर सकते हैं:

SELECT NEW DepartmentEmployeeCount(D.DEPARTMENT_NAME, count(E.id)) from Department D left join D.employees E GROUP BY D.DEPARTMENT_NAME 

या यदि आपने अभी गिनती (*) का चयन किया गया था आप क्वेरी परिणाम को केवल संख्या में डाला जा सकता है।

वैकल्पिक रूप से, DepartmentEmployeeCount वर्ग के बिना भी ऐसा ही करने के लिए, आप बाहर छोड़ सकता नई है, तो:

SELECT D.DEPARTMENT_NAME, count(E.id)  

यह एक List<Object[]> वापसी होगी जहां प्रत्येक सूची आइटम 2 तत्वों की एक सरणी था, departmentName और गिनती ।

टिप्पणियों में अपने बाद के प्रश्न का उत्तर देने के लिए, विभाग के सभी क्षेत्रों को एक क्षणिक कर्मचारी काउंटर फ़ील्ड को पॉप्युलेट करने के लिए, एक सुझाव 2 प्रश्न करना होगा। यह अभी भी आपकी मूल क्वेरी (प्रत्येक कर्मचारी गणना के लिए उप-चयन) से अधिक कुशल होगा।

तो एक क्वेरी विभागों

SELECT D from Department D 

आप दे रही है पढ़ने के लिए एक List<Department>

फिर एक 2 एक अस्थायी सरणी वापस भेजने:

SELECT D.DEPARTMENT_ID, count(E.id) from Department D left join D.employees E GROUP BY D.DEPARTMENT_ID 

DEPARTMENT_ID और गिनती के साथ आप एक List<Object[]> दे रही है इस में।

फिर आप अपनी पहली सूची में क्षणिक गिनती संपत्ति को अपडेट करने के लिए दूसरी सूची का उपयोग करते हैं। (आप इस लुकअप को आसान बनाने के लिए मानचित्र में चयन करने का प्रयास कर सकते हैं, लेकिन मुझे लगता है कि यह एक हाइबरनेट सुविधा है)।

+0

आपके उत्तर के लिए @MattR धन्यवाद। यह समाधान इस सरल उदाहरण के लिए काम कर सकता है। लेकिन क्या होगा यदि (ए) विभाग तालिका में NAME के ​​अलावा कई अन्य कॉलम हैं और मैं स्पष्ट रूप से उन सभी को कन्स्ट्रक्टर में सूचीबद्ध नहीं करना चाहता हूं और (बी) मैं अभी भी इसे डिपार्टमेंट इकाई की संपत्ति के रूप में रखना चाहता हूं (LAZY लाने के साथ प्रकार) बस मामले में कहीं और सुलभ होने के लिए। – AndreiM

+0

अच्छा सवाल, मैंने कोशिश नहीं की है लेकिन मुझे लगता है * आप कन्स्ट्रक्टर में इकाई वर्गों का उपयोग कर सकते हैं (इसलिए आपको सभी इकाई गुणों को चुनने की आवश्यकता नहीं होगी)। अगर मुझे इसे आजमाने का मौका मिलता है तो मैं अपना जवाब अपडेट करूंगा ... यानी आपके पास एक डिपार्टमेंट कर्मचारी वर्ग (कहना) हो सकता है जिसमें एक कंस्ट्रक्टर डिपार्टमेंट कर्मचारी (विभाग, इंटीजर) था और नए विभाग के कर्मचारियों का चयन करें (डी, गिनती (ई.आईडी))) - जो कुछ भी आप पूछ रहे हैं उसके करीब नहीं है ... – MattR

+0

ठीक है, मैं इस बारे में एक लंच के बारे में सोच रहा था, इसलिए कुछ अतिरिक्त जानकारी अपडेट की गई। यदि आप किसी भी सुझाव का प्रयास करते हैं या बेहतर समाधान ढूंढते हैं, तो कृपया – MattR

3

विकल्प 1: मैंने यह सुझाव दिया क्योंकि आपको कन्स्ट्रक्टर रूट मैटआर का सुझाव नहीं था।आपने कई बार "व्यू" शब्द का उल्लेख किया है, और मुझे पता है कि आप उपयोगकर्ता को देखने के बारे में बात कर रहे थे, लेकिन क्यों नहीं अपने डेटाबेस में एक दृश्य स्थापित करें जिसमें गणना किए गए कॉलम शामिल हैं और फिर केवल पढ़ने वाली इकाई बनाएं जो गणना के लिए मानचित्र करे कॉलम?

विकल्प 2: दृश्य बनाने के इच्छुक नहीं होने के बारे में आपकी टिप्पणी के जवाब में। आप एक कंटेनर ऑब्जेक्ट बना सकते हैं जिसमें इकाई और गणना कॉलम हो, तो मैटआर सुझावों की तरह, आप अपने चयन में एक नया उपयोग करते हैं। कुछ की तरह:

public class DepartmentInfo { 
    private Department department; 

    // this might have to be long or something 
    // just see what construct JPA tries to call 
    private int employeeCount; 

    public DepartmentInfo(Department d, int count) { 
     department = d; 
     employeeCount = count; 
    } 
    // getters and setters here 
} 

फिर अपने चयन हो जाता है

SELECT new my.package.DepartmentInfo(D, 
     (SELECT COUNT(*) FROM EMPLOYEE E WHERE E.DEPARTMENT_ID = D.DEPARTMENT_ID)) 
FROM DEPARTMENT D 

कि के साथ आप DepartmentInfo उपयोग कर सकते हैं गुण आप में रुचि रखते हैं पाने के लिए

+0

यह संभव है, वास्तव में। लेकिन मैं जो चाहता हूं वह मेरी मौजूदा इकाई के लिए एक अतिरिक्त संपत्ति है, जिसका उपयोग मैं एक पृष्ठ (और, संभवतः, कहीं और) पर कर सकता हूं। क्या यह वास्तव में एक और दृश्य और इसके लिए एक और इकाई बनाने लायक है? – AndreiM

+0

आप जो चाहते हैं _right now_ आपकी मौजूदा इकाई के लिए एक पृष्ठ पर संभवतः एक और अतिरिक्त उपयोग करने के लिए एक अतिरिक्त संपत्ति है। और भविष्य में संभवतः 3 और अधिक संपत्तियों के साथ संभवतः 3 और अधिक और इतने पर। किसी भी मामले में, मैंने अपने उत्तर में विकल्प 2 जोड़ा है। – digitaljoel

+0

धन्यवाद, @ डिजीटलजोएल, अब तक इस परिदृश्य में सबसे इष्टतम दृष्टिकोण की तरह दिखता है। – AndreiM

1

आप के रूप में अपने इकाई में एक सदस्य बना सकते हैं। एक अतिरिक्त कॉलम, और फिर इसे अपनी क्वेरी में उपनाम के साथ संदर्भित करें। @Column एनोटेशन में कॉलम नाम उपनाम से मेल खाना चाहिए।

कहें, अपनी मूल क्वेरी के लिए, आप निम्न के रूप में countEmployees सदस्य जोड़ सकते हैं। इसके अलावा insertable=false और updatable=false तो इकाई प्रबंधक अभ्यस्त डालने या अद्यतन बयान में शामिल करने की कोशिश जोड़ें:

public class Department { 

    @Column(name="DEPARTMENT_ID") 
    Long departmentId; 

    @Column(name="DEPARTMENT_NAME") 
    String departmentName; 

    @Column(name="countEmployees", insertable=false, updatable=false) 
    Long countEmployees; 

    //accessors omitted 

} 

और आपकी क्वेरी:

SELECT D.DEPARTMENT_NAME, 
(SELECT COUNT(*) FROM EMPLOYEE E WHERE E.DEPARTMENT_ID = D.DEPARTMENT_ID) AS countEmployees 
FROM DEPARTMENT D 

यह भी जब स्प्रिंग डाटा जेपीए डेटा संग्रह स्थान के साथ काम कर लागू होता है।

+0

क्या आप एक जेपीए क्वेरी का उपयोग करके ऐसा ही कर सकते हैं, मूल नहीं? – Arthur

+0

यह रणनीति काम नहीं करती है। – Partha

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