The main goal of this project is to explore basic query features of
JPA 2.1
specification:
- JPQL
- JPA Criteria API (typesafe with auto-generated static metamodels)
As a JPA
provider we choose Hibernate
to test some of HQL
.
- Flyway - constructs the database & provide datafeed in two migrations.
Ensures data coherence by checking if schema in database is up to date (
by validating additional database table concerning migrations:
flyway_schema_history
).
Reference: https://flywaydb.org/documentation/ - JPA 2.1
Reference: Pro JPA 2 2nd Edition
Reference: JSR 338: JavaTM Persistence API, Version 2.1 - Hibernate - provider of
JPA 2.1
specification. We don't useEclipseLink
despite the fact that it isreference implementation
ofJPA 2.1
because apart fromJPQL
we want to exploreHQL
as a more powerful query language.
Reference: Java Persistence with Hibernate Second Edition
Reference: Hibernate Interview Questions and Answers - Jupiter & AssertJ - to test result sets (
AssertJ
has very convinient methods to comparing lists regardless order).
- The main idea is to explore
JPA Criteria API
by writing a querys inJPQL
orHQL
, then to try re-write them inJPA Criteria API
& check result-sets identity. - Comparing equality of result sets with
JUnit
&hamcrest
:but we decide to useimport static org.hamcrest.Matchers.containsInAnyOrder; ... Assert.assertThat(entityManager.createQuery(cc_query) .getResultList(), containsInAnyOrder(jpql_query.getResultList().toArray()));
Jupiter
&AssertJ
(more expressive):import static org.assertj.core.api.Assertions.assertThat; ... assertThat(entityManager.createQuery(cc_query).getResultList()) .containsExactlyInAnyOrderElementsOf(jpql_query.getResultList());
src/main/java
: entities, utility classes & META-INF
folder with
persistence.xml
resources/db/migration
: Flyway
migrations as SQL
scripts
test/java
: showcase of JPQL
, HQL
& Criteria API
with tests
target/generated-sources
: static metamodels of entities
-
We have to classes with nearly the same content:
Tests
andTestsWithFullTypeSafe
. The only difference is that in the first class we use strings to denote fields while in the letter we use static metamodels. -
Example:
- From
Tests
:orderBy(cb.asc(cc_query_root.get("title")));
- From
TestsWithFullTypeSafe
:orderBy(cb.asc(cc_query_root.get(Book_.title)));
- From
-
All methods are quite simple & straightforward use of
Criteria API
.
The most interesting are:getBookstoresWithMostExpensiveBook()
- we show how to use subqueriesgetBookstoresThatHaveTitle()
- we show how to reference aFROM
expression of the parent query in theFROM
clause of a subquerygetBookstoresThatHaveAtLeastOneBookWrittenBy()
- we show how to reference aJOIN
expression of the parent query in theFROM
clause of a subquerycountBooksByGenre()
- we show how to useTuple
with aliasesgetBookstoresWithCountBooksAndPriceAverage()
- we show how to usemultiselect
with dedicated class
They are auto-generated by maven-compiler-plugin
.
All you need to do is:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<compilerArguments>
<processor>org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor</processor>
</compilerArguments>
</configuration>
</plugin>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-jpamodelgen</artifactId>
<version>5.2.17.Final</version>
<scope>provided</scope>
</dependency>
Mark target/generated-sources
as a Generated Sources Root
.
In IntelliJ
just left-click on target/generated-sources
->
Mark Directory As
-> Generated Sources Root
.