2012-02-07 10 views
8

Jak mogę, stosując kryteria WZP API wykonaj następujące czynności:Jak countDistinct na wielu kolumnach

select count(distinct column1, column2) from table 

Robi to na jednej kolumnie/ścieżka jest prosta przy użyciu CriteriaBuilder.countDistinct, ale w jaki sposób mogę to zrobić na dwie ścieżki/kolumny?

+0

uwaga : niektóre dbms nie obsługują tego rodzaju składni. nie wiem, czy ktokolwiek to robi. AFAIK Hibernate Doe nie obsługuje tego – Firo

+0

Rzeczywiście wydaje się, że jest to problem. MySQL ma, ale prawdopodobnie niezbyt często, –

+0

czy znalazłeś w międzyczasie jakieś rozwiązanie twojego pytania? Mam taką samą sytuację i nie znajduję dla niej rozwiązania. –

Odpowiedz

3

Tutaj jest późno odpowiedź :-) choć nie jestem pewien, czy wszystko się zmieniło.

Ostatnio napotkał tę samą potrzeby i obejść niego przy concat, to poprzez łączenie kolumny do kolumny pseudo, a następnie na kolumnie countDistinct pseudo.

Ale nie mogłem użyć criteriaBuilder.concat ponieważ generowane JPQL użyciu || do konkatenacji, który Hibernate had trouble with.

szczęście istnieje @Formula zatem ja odwzorowane kolumnę pseudo na polu z @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; 
} 

ten sposób wreszcie mogę użyć pola concated dla CriteriaBuilder.countDistinct:

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

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

I Żałuję, że JPA (lub, mam nadzieję, że już) nie będzie obsługiwać countDistinct z wieloma kolumnami, wtedy można by uniknąć tych wszystkich bałaganów.

+0

Ach, tak, to powinno zadziałać. Brzydki hack, ale przynajmniej działa! :) –

+0

@PiotrBlasiak, cieszę się, że to działa również dla ciebie :-) – ryenus

+0

Naprawdę rozwiązałem to za pomocą natywnego zapytania i prawdopodobnie będzie ono działało lepiej niż twoje rozwiązanie, ale widzę, jak twoje rozwiązanie będzie działać. –

0

Wydaje się, nie ma sposobu, aby to zrobić z JPA2

1

Do tego zadania można użyć dialektu hibernacji. Aby to zrobić, utwórz własny dialekt, który rozszerza dialekt DB, który był używany (list of all dialects), a następnie zarejestruj nową funkcję. Na przykład, używam MySQL 5 z silnikiem InnoDB:

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

Po następnie dodać nową właściwość w persistence.xml:

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

I teraz można korzystać z tej funkcji:

// 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 
Powiązane problemy