2012-01-29 35 views
5

Tôi mới trong JPA và muốn triển khai một JPA DAO chung và cần tìm số hàng của một tập kết quả truy vấn để triển khai phân trang. Sau khi tìm kiếm trên web, tôi không thể tìm thấy cách thực tế để làm điều đó. Đây là mã được đề xuất trong nhiều bài viết:Làm thế nào để đếm số hàng của JPA 2 CriteriaQuery trong một JPA DAO chung?

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(); 
} 

Tuy nhiên, mã đó không hoạt động khi sử dụng join. Có cách nào để đếm các hàng của tập hợp kết quả truy vấn bằng cách sử dụng API tiêu chí JPA không?

UPDATE: đây là mã mà tạo CriteriaQuery:

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

và một số tham gia có thể được thêm vào thư mục gốc đến khi truy vấn đã được thực hiện:

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

và ngoại lệ được tạo ra là như:

org.hibernate.hql.ast.QuerySyntaxException: Đường dẫn không hợp lệ: 'generatedAlias1.id' [select count (generatedAlias0) từ entity.Entity như generatedAlias0 nơi (generatedAlias0.id> = 13L) và ( (generatedAlias1.id < = 34L))]

mà generatedAlias1 nên được trên Entity và generatedAlias0 nên được trên các hiệp hội mà tôi tham gia vào đó. Lưu ý rằng tôi thực hiện Tham gia đúng cách vì khi tôi thực hiện truy vấn mà không tính truy vấn, nó thực hiện mà không có lỗi và tham gia hoạt động đúng nhưng khi tôi cố gắng thực hiện truy vấn đếm nó ném ngoại lệ.

+0

Bạn có thể chỉ cho chúng tôi cách bạn đã xác định CriteriaQuery tiêu chí – perissf

+0

@perissf Tôi đã cập nhật bài đăng hay không. – stacker

+0

Kiểm tra một số câu trả lời khác cho các vấn đề tương tự: http://stackoverflow.com/questions/9001289/jpa-hibernate-criteriabuilder-how-to-create-query-using-relationship-object/9002225#9002225 và http: // stackoverflow.com/questions/9025196/how-to-use-jpa-criteria-api-when-joining-many-tables/9025656#9025656 – perissf

Trả lời

1

Tôi không thể cho bạn biết vấn đề của bạn ở đâu, nhưng tôi có thể cho bạn biết rằng các truy vấn đếm có tham gia hoạt động tốt, ít nhất là ở eclipselink jpa. Tôi đoán là đây là công cụ chuẩn, vì vậy nó cũng hoạt động được ở chế độ ngủ đông. Tôi sẽ bắt đầu bằng cách đơn giản hóa mã của bạn để nắm bắt được vấn đề ở đâu. Tôi thấy rằng bạn đã sao chép một số phần truy vấn tiếp theo từ truy vấn chính của mình. Có lẽ bạn có thể cố gắng thay đổi một chút cách tiếp cận này, chỉ cho mục đích gỡ lỗi.

Những gì tôi làm thường là:

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); 

Nhìn vào pseudo-code của bạn, có vẻ như bạn đang sử dụng lớp sai trong tham gia phương pháp: nó phải là lớp học bắt đầu, không phải là lớp đối tượng.

+0

Đọc câu trả lời đơn giản của bạn sau một đêm ngon trời khiến tôi mất 10 giờ đấu tranh với công cụ truy vấn và tiêu chí tham gia này ...:) – Raindal

6

Tôi đã làm điều này:

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); 
    } 
} 

tất nhiên bạn không cần root như tham số đầu vào bạn có thể nhận được nó từ tiêu chí truy vấn,

+0

Câu trả lời hay, cảm ơn bạn đã chia sẻ công việc của mình. –

3

@ lubo08 cho câu trả lời đúng - thanh danh cho anh ta . Nhưng đối với hai trường hợp góc/code mình sẽ không làm việc:

  • Khi hạn chế tiêu chí truy vấn của sử dụng bí danh cho tham gia - sau đó COUNT cũng đòi hỏi những bí danh để được thiết lập.
  • Khi sử dụng tiêu chí truy vấn lấy tham gia [root.fetch(..) thay vì root.join(..)]

Vì vậy, cho đầy đủ Tôi dám để cải thiện mình/giải pháp của mình và trình bày dưới đây:

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); 
    } 
} 

Mặc dù nó vẫn là không hoàn hảo, bởi vì chỉ có một gốc được vinh danh.
Nhưng tôi hy vọng nó sẽ giúp ai đó.

Các vấn đề liên quan