Grupperings- og aggregeringsfunksjoner
Du har allerede funnet ut hvordan du gjør enkle forespørsler til Criteria API. La oss se hvordan du lager mer komplekse søk.
For eksempel ønsker vi å skrive en spørring for å bestemme antall ansatte i en bedrift. Slik vil det se ut i HQL:
select count(*) from Employee
Og slik på Criteria API:
CriteriaQuery<Long> critQuery = builder.createQuery(Long.class);
critQuery.select(builder.count(critQuery.from(Employee.class)));
Den komplette Java-koden vil se slik ut:
CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<Long> critQuery = builder.createQuery(Long.class);
critQuery.select(builder.count(critQuery.from(Employee.class)));
Query<Long> query = session.createQuery(critQuery);
Long count = query.getSingleResult();
Og det er det samme med HQL:
String hqlQuery = "select count(*) from Employee";
Query<Long> query = session.createQuery(hqlQuery);
Long count = query.getSingleResult();
La oss nå prøve å beregne gjennomsnittslønnen i selskapet. HQL-spørringen vil se slik ut:
select avg(salary) from Employee
Og slik på Criteria API:
CriteriaQuery<Double> critQuery = builder.createQuery(Double.class);
critQuery.select(builder.avg( critQuery.from(Employee.class).get("salary")));
Den komplette Java-koden vil se slik ut:
CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<Double> critQuery = builder.createQuery(Double.class);
critQuery.select(builder.avg( critQuery.from(Employee.class).get("salary")));
Query<Double> query = session.createQuery(critQuery);
Double avgSalary = query.getSingleResult();
KriterierOppdatering
Å endre en tabell er like enkelt som å hente data fra den. For å gjøre dette har CriteriaBuilder en spesiell metode - createCriteriaUpdate() , som lager et objektCriteriaUpdate<T>Den som oppdaterer enhetene i databasen.
La oss heve lønnen til ansatte som mottar mindre enn 10 tusen. Slik vil dette HQL-søket se ut:
update Employee set salary = salary+20000 where salary<=10000
Og slik vil det se ut på Criteria API:
CriteriaUpdate<Employee> criteriaUpdate = builder.createCriteriaUpdate(Employee.class);
Root<Employee> root = criteriaUpdate.from(Employee.class);
criteriaUpdate.set("salary", "salary+20000");
criteriaUpdate.where(builder.lt(root.get("salary"), 10000));
Transaction transaction = session.beginTransaction();
session.createQuery(criteriaUpdate).executeUpdate();
transaction.commit();
Kriterier Slett
Og å slette poster er enda enklere enn å endre dem. For å gjøre dette er det en spesiell metode createCriteriaDelete() , som lager et objektKriterier Slett<T>.
La oss kutte alle ansatte som ikke har noen verdi: lønnen deres er mindre enn 10 tusen. Slik vil dette HQL-søket se ut:
delete from Employee where salary<=10000
Og slik vil det se ut på Criteria API:
CriteriaDelete<Employee> criteriaDelete = builder.createCriteriaDelete(Employee.class);
Root<Employee> root = criteriaDelete.from(Employee.class);
criteriaDelete.where(builder.lt(root.get("salary"), 10000));
Transaction transaction = session.beginTransaction();
session.createQuery(criteriaDelete).executeUpdate();
transaction.commit();
Fordeler med Criteria API
Så hva er fordelen med Criteria API? Spørsmål er tungvint, HQL vil definitivt være mer kompakt.
For det første er ikke HQL-spørringer så korte hvis du trenger å sende parametere til dem. Sammenligne:
Vi vurderer antall ansatte med en lønn på under 10 tusen |
---|
HQL |
|
Kriterier API |
|
For det andre er det veldig ofte en situasjon der en spørring må konstrueres dynamisk. For eksempel har du en nettside som filtrerer ansatte, leiligheter og hva som helst. Og hvis en parameter ikke er viktig for brukeren, indikerer han det rett og slett ikke. Følgelig sendes null til serveren i stedet.
Her er oppgaven din: å velge ansatte med et bestemt yrke (yrke), lønn (lønn) og ansettelsesår (ÅR (tiltredelsesdato)). Men hvis en parameterverdi er null, så ikke bruk den i filteret.
Da vil HQL-spørringen se omtrent slik ut:
from Employee
where (occupation = :ocp)
and (salary = :sal)
and ( YEAR(join_date) = :jny)
Men det vil ikke fungere riktig, siden vi vil at hvis "jny"-parameteren var null, vil forespørselen se slik ut:
from Employee
where (occupation = :ocp)
and (salary = :sal)
Vi kan prøve å omskrive forespørselen med å sjekke parameteren for null, så får vi noe slikt:
from Employee
where (occupation = :ocp or :ocp is null)
and (salary = :sal or :sal is null)
and ( YEAR(join_date)= :jny or :jny is null)
Ser du hvordan virkeligheten blir mer komplisert? Virkeligheten er ofte slik :)
Men filteret kan være enda mer komplisert. Hva med å søke etter brukere som har oppgaver med ordet «kjøp» i seg? Eller brukere som har forfalte oppgaver?
from Employee
where (occupation = :ocp)
and (salary = :sal)
and (YEAR(join_date) = :jny)
and (tasks.name like '%buy%')
and (tasks.deadline < curdate())
Hvis du skriver eller er null et sted i en slik spørring , vil ikke dette kansellere sammenføyningen mellom tabeller.
Så i praksis, når du gjør et komplekst filter på feltene til flere tabeller, kan Criteria API bare hjelpe deg. Så det går.
Flere detaljer finner du i den offisielle dokumentasjonen .