2012-02-07 33 views
8

Làm thế nào tôi có thể sử dụng các tiêu chuẩn JPA API làm như sau:Làm thế nào để countDistinct trên nhiều cột

select count(distinct column1, column2) from table 

Làm điều này trên một cột/path là đơn giản sử dụng CriteriaBuilder.countDistinct, nhưng làm thế nào tôi có thể làm điều này trên hai đường dẫn/cột?

+0

lưu ý : một số dbms không hỗ trợ loại cú pháp này. tôi không biết nếu có. AFAIK Hibernate doe không hỗ trợ điều này – Firo

+0

Thực ra điều đó có vẻ là vấn đề. MySQL có nhưng có lẽ không phải là rất phổ biến –

+0

bạn đã tìm thấy trong khi chờ đợi bất kỳ giải pháp cho câu hỏi của bạn? Tôi có tình huống tương tự và không tìm ra giải pháp cho nó. –

Trả lời

3

Dưới đây là một câu trả lời cuối :-) mặc dù tôi không chắc chắn nếu điều đã thay đổi.

Gần đây tôi gặp phải những nhu cầu rất giống nhau, và làm việc xung quanh nó bằng cách sử concat, ví dụ, bằng cách kết hợp các cột thành một cột giả, sau đó countDistinct trên cột giả.

Nhưng tôi không thể sử dụng criteriaBuilder.concat vì nó đã tạo JPQL bằng cách sử dụng || cho nối, trong đó Hibernate had trouble with.

May mắn thay có @Formula, do đó, tôi lập bản đồ cột giả đến một lĩnh vực với @Formula:

@Entity 
public class MyEntity { 
    @Column(name="col_a") 
    private String colA; 

    @Column(name="col_b") 
    private String colB; 

    @Formula("concat(col_a, col_b)") // <= THE TRICK 
    private String concated; 
} 

Bằng cách này tôi cuối cùng đã có thể sử dụng trường concated cho CriteriaBuilder.countDistinct:

//... 
Expression<?> exp = criteriaBuilder.countDistinct(entity.get("concated")); 
criteriaQuery.select(exp); 

TypedQuery<Long> query = entityManager.createQuery(criteriaQuery); 
return query.getSingleResult(); 

tôi mong muốn JPA sẽ (hoặc hy vọng đã) hỗ trợ countDistinct với nhiều cột, sau đó tất cả những mớ hỗn độn này có thể tránh được.

+0

Ah, có điều đó sẽ hoạt động. Ugly hack nhưng ít nhất nó hoạt động! :) –

+0

@PiotrBlasiak, vui vì nó hoạt động cho bạn :-) – ryenus

+0

Tôi thực sự đã giải quyết nó bằng cách sử dụng truy vấn gốc và nó có khả năng hoạt động tốt hơn giải pháp của bạn, nhưng tôi có thể xem giải pháp của bạn sẽ hoạt động như thế nào. –

0

Có vẻ như không có cách nào để làm điều này với JPA2

1

Bạn có thể sử dụng phương ngữ ngủ đông cho tác vụ này. Để làm điều này, hãy tạo phương ngữ của riêng bạn, mở rộng phương ngữ của DB được sử dụng (list of all dialects), và sau đó đăng ký chức năng mới. Ví dụ, tôi sử dụng MySQL 5 với động cơ InnoDB:

public final class MyDialect extends MySQL5InnoDBDialect { 
    public MyDialect() { 
     super(); 
     registerFunction("pairCountDistinct", new SQLFunctionTemplate(LongType.INSTANCE, "count(distinct ?1, ?2)")); 
    } 
} 

Sau khi sau đó thêm tài sản mới trong persistence.xml:

<property name="hibernate.dialect" value="com.example.dialect.MyDialect" /> 

Và bây giờ bạn có thể sử dụng chức năng này:

// some init actions 
final CriteriaBuilder builder = entityManager.getCriteriaBuilder(); 
final CriteriaQuery<Long> criteria = builder.createQuery(Long.class); 
final Root<SomeEntity> root = criteria.from(SomeEntity.class); 
criteria.select(builder.function("pairCountDistinct", Long.class, root.get(SomeEntity_.field1), root.get(SomeEntity_.field2))); 
final long result = entityManager.createQuery(criteria).getSingleResult(); 
// some close actions 
Các vấn đề liên quan