2012-01-29 17 views
5

मैं जेपीए में नया हूं और एक जेनेरिक जेपीए डीएओ को कार्यान्वित करना चाहता हूं और पेजिनेशन को लागू करने के लिए एक क्वेरी परिणाम सेट की पंक्तियों की संख्या को खोजने की आवश्यकता है। वेब खोजने के बाद, मुझे ऐसा करने का व्यावहारिक तरीका नहीं मिल रहा है।एक जेपीए 2 CriteriaQuery की पंक्तियों की संख्या को सामान्य जेपीए डीएओ में कैसे गिनें?

public <T> Long findCountByCriteria(CriteriaQuery<?> criteria) { 
    CriteriaBuilder builder = em.getCriteriaBuilder(); 

    CriteriaQuery<Long> countCriteria = builder.createQuery(Long.class); 
    Root<?> entityRoot = countCriteria.from(criteria.getResultType()); 
    countCriteria.select(builder.count(entityRoot)); 
    countCriteria.where(criteria.getRestriction()); 

    return em.createQuery(countCriteria).getSingleResult(); 
} 

हालांकि, उस कोड जब join का उपयोग कर काम नहीं करता है: यहाँ कोड कई लेख में सुझाव दिया है। जेपीए मानदंड एपीआई का उपयोग कर एक क्वेरी परिणाम सेट की पंक्तियों को गिनने का कोई तरीका है?

अद्यतन: यहाँ कोड है कि CriteriaQuery बनाने है:

CriteriaQuery<T> queryDefinition = criteriaBuilder.createQuery(this.entityClass); 
    Root<T> root = queryDefinition.from(this.entityClass); 

और कुछ मिलती जड़ में जोड़ा जा सकता है जब तक क्वेरी निष्पादित किया गया है:

public Predicate addPredicate(Root<T> root) { 
       Predicate predicate = getEntityManager().getCriteriaBuilder().ge(root.join(Entity_.someList).get("id"), 13); 
       return predicate; 
} 

और उत्पन्न अपवाद नहीं है जैसे:

org.hibernate.hql.ast.QuerySyntaxException: अमान्य पथ: 'generatedAlias1.id' [चयन गणना (generatedAlias0) generatedAlias0 रूप entity.Entity से जहां (generatedAlias0.id> = 13L) और ( (generatedAlias1.id < = 34L))]

जो generatedAlias1 चाहिए अस्तित्व पर रहें और जेनरेट किया गया एलीस 0 उस संगठन पर होना चाहिए जो मैं उस पर शामिल हुआ। ध्यान दें कि मैं लागू करता हूं ठीक से जुड़ें क्योंकि जब मैं गिनती क्वेरी के बिना क्वेरी निष्पादित करता हूं तो यह त्रुटि के बिना निष्पादित करता है और जॉइन ठीक से काम करता है लेकिन जब मैं गिनती क्वेरी निष्पादित करने का प्रयास करता हूं तो यह अपवाद फेंकता है।

+0

क्या आप हमें दिखा सकते हैं कि आपने CriteriaQuery मानदंड – perissf

+0

@perissf मैंने पोस्ट को अपडेट किया है। – stacker

+0

समान समस्याओं के कुछ अन्य उत्तरों देखें: http://stackoverflow.com/questions/9001289/jpa-hibernate-criteriabuilder-how-to-create-query-using-relationship-object/9002225#9002225 और http: // stackoverflow.com/questions/9025196/how-to-use-jpa-criteria-api-when-joining-many-tables/9025656#9025656 – perissf

उत्तर

1

मैं आपको यह नहीं बता सकता कि आपकी समस्या कहां है, लेकिन मैं आपको बता सकता हूं कि कम से कम eclipselink जेपीए में शामिल होने के साथ प्रश्नों की गिनती अच्छी तरह से काम करती है। मेरा अनुमान है कि यह मानक सामान है, इसलिए इसे हाइबरनेट में भी काम करना चाहिए। समस्या को पकड़ने के लिए मैं आपके कोड को सरल बनाकर शुरू करूंगा। मुझे लगता है कि आपने अपनी मुख्य क्वेरी से अपनी cont क्वेरी के कुछ टुकड़े कॉपी किए हैं। शायद आप डीबगिंग उद्देश्य के लिए, इस दृष्टिकोण को थोड़ा सा बदलने की कोशिश कर सकते हैं।

क्या मैं आमतौर पर करते हैं:

CriteriaQuery cqCount = builder.createQuery(); 
Root<T> root = cq.from(T.class); 
cqCount.select(builder.count(root)); 
ListJoin<T, Entity> join = root.join(T_.someList); 
Predicate predicate = builder.ge(join.get(Entity_.id), "myId"); 
cqCount.where(predicate); 
TypedQuery<Long> q = em.createQuery(cqCount); 

अपने छद्म कोड को देखते हुए, ऐसा लगता है कि आप में शामिल होने के विधि में गलत वर्ग का उपयोग कर रहे हैं: यह प्रारंभिक वर्ग, नहीं लक्ष्य वर्ग होना चाहिए। उसे के लिए प्रशंसा -

public Long getRowCount(CriteriaQuery criteriaQuery,CriteriaBuilder criteriaBuilder,Root<?> root){ 
    CriteriaQuery<Long> countCriteria = criteriaBuilder.createQuery(Long.class); 
    Root<?> entityRoot = countCriteria.from(root.getJavaType()); 
    entityRoot.alias(root.getAlias()); 
    doJoins(root.getJoins(),entityRoot); 
    countCriteria.select(criteriaBuilder.count(entityRoot)); 
    countCriteria.where(criteriaQuery.getRestriction()); 
    return this.entityManager.createQuery(countCriteria).getSingleResult(); 
} 

private void doJoins(Set<? extends Join<?, ?>> joins,Root<?> root_){ 
    for(Join<?,?> join: joins){ 
     Join<?,?> joined = root_.join(join.getAttribute().getName(),join.getJoinType()); 
     doJoins(join.getJoins(), joined); 
    } 
} 

private void doJoins(Set<? extends Join<?, ?>> joins,Join<?,?> root_){ 
    for(Join<?,?> join: joins){ 
     Join<?,?> joined = root_.join(join.getAttribute().getName(),join.getJoinType()); 
     doJoins(join.getJoins(),joined); 
    } 
} 
बेशक आप इनपुट पैरामीटर के रूप में रूट की जरूरत नहीं है आप मापदंड क्वेरी से यह हो सकता है की

,

+0

अच्छी रात के बाद अपना सरल उत्तर पढ़ना मुझे 10 घंटों के संघर्ष से बाहर निकाला इस क्वेरी और मानदंड सामग्री में शामिल होने के साथ ...:) – Raindal

6

मैं यह कर दिया है । लेकिन दो कोने मामलों के लिए उसकी/उसके कोड काम नहीं करेगा:

  • मापदंड क्वेरी के प्रतिबंध के लिए मिलती है उपनाम का उपयोग करते हैं - तो COUNT भी इन अन्य नामों स्थापित किया जाना आवश्यक है।
  • मापदंड क्वेरी उपयोग लाने जब में शामिल होने [root.fetch(..) बजाय root.join(..) की]
संपूर्णता के लिए

तो मैं उसकी/उसके समाधान और वर्तमान नीचे में सुधार करने की हिम्मत:

public <T> long count(final CriteriaBuilder cb, final CriteriaQuery<T> criteria, 
     Root<T> root) { 
    CriteriaQuery<Long> query = createCountQuery(cb, criteria, root); 
    return this.entityManager.createQuery(query).getSingleResult(); 
} 

private <T> CriteriaQuery<Long> createCountQuery(final CriteriaBuilder cb, 
     final CriteriaQuery<T> criteria, final Root<T> root) { 

    final CriteriaQuery<Long> countQuery = cb.createQuery(Long.class); 
    final Root<T> countRoot = countQuery.from(criteria.getResultType()); 

    doJoins(root.getJoins(), countRoot); 
    doJoinsOnFetches(root.getFetches(), countRoot); 

    countQuery.select(cb.count(countRoot)); 
    countQuery.where(criteria.getRestriction()); 

    countRoot.alias(root.getAlias()); 

    return countQuery.distinct(criteria.isDistinct()); 
} 

@SuppressWarnings("unchecked") 
private void doJoinsOnFetches(Set<? extends Fetch<?, ?>> joins, Root<?> root) { 
    doJoins((Set<? extends Join<?, ?>>) joins, root); 
} 

private void doJoins(Set<? extends Join<?, ?>> joins, Root<?> root) { 
    for (Join<?, ?> join : joins) { 
     Join<?, ?> joined = root.join(join.getAttribute().getName(), join.getJoinType()); 
     joined.alias(join.getAlias()); 
     doJoins(join.getJoins(), joined); 
    } 
} 

private void doJoins(Set<? extends Join<?, ?>> joins, Join<?, ?> root) { 
    for (Join<?, ?> join : joins) { 
     Join<?, ?> joined = root.join(join.getAttribute().getName(), join.getJoinType()); 
     joined.alias(join.getAlias()); 
     doJoins(join.getJoins(), joined); 
    } 
} 

हालांकि यह अभी भी है सही नहीं, क्योंकि केवल एक रूट को सम्मानित किया जाता है।
लेकिन मुझे उम्मीद है कि यह किसी की मदद करेगा।

+0

अच्छा जवाब, आपके काम को साझा करने के लिए धन्यवाद। –

3

@ lubo08 सही जवाब दिया:

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