Querydsl fin jug - june 2012
-
Upload
timo-westkaemper -
Category
Technology
-
view
2.258 -
download
0
description
Transcript of Querydsl fin jug - june 2012
![Page 1: Querydsl fin jug - june 2012](https://reader033.fdocuments.net/reader033/viewer/2022050919/5475832eb4af9f9d0a8b5aff/html5/thumbnails/1.jpg)
Querydsl
Type-safe queries for Java
Timo Westkämper@timowest
www.querydsl.com
![Page 2: Querydsl fin jug - june 2012](https://reader033.fdocuments.net/reader033/viewer/2022050919/5475832eb4af9f9d0a8b5aff/html5/thumbnails/2.jpg)
Before Querydsl
● Queries as strings within code
TypedQuery<Person> query = em.createQuery( "select person from Person person " +
"where person.firstName = ?1", Person.class); query.setParameter(1, "Max"); List<Person> persons = query.getResultList();
● Must remember query syntax, domain classes, properties and relationships● Syntax reference always at hand● Domain model/schema reference at hand● High cognitive overhead● Error-prone
![Page 3: Querydsl fin jug - june 2012](https://reader033.fdocuments.net/reader033/viewer/2022050919/5475832eb4af9f9d0a8b5aff/html5/thumbnails/3.jpg)
Before Querydsl
● Dynamic query building by string concatenation● Very hard with multiple joins, ordering and complex
conditionals depending on actual parameters
StringBuilder where = new StringBuilder(); if (firstName != null) where.append("person.firstName = :firstName"); ... TypedQuery<Person> query = entityManager.createQuery( "select person from Person person where " + where, Person.class); if (firstName != null) query.setParameter("firstName", firstName); ... List<Person> persons = query.getResultList();
![Page 4: Querydsl fin jug - june 2012](https://reader033.fdocuments.net/reader033/viewer/2022050919/5475832eb4af9f9d0a8b5aff/html5/thumbnails/4.jpg)
Before Querydsl
● Query syntax validation by execution is slow and breaks the flow
● Each back-end has its own query language and API● SQL-like for JPA and JDO, but not for MongoDB
and Lucene● Verbose parameter binding by name or position to
parameter placeholders of a prepared statement● Or risk injection attack if parameters are directly
concatenated to query
![Page 5: Querydsl fin jug - june 2012](https://reader033.fdocuments.net/reader033/viewer/2022050919/5475832eb4af9f9d0a8b5aff/html5/thumbnails/5.jpg)
Before Querydsl
● Hibernate Criteria API as an alternative? ● Better for dynamic queries and has easier
parameter binding, but...● Lacking expressivity, unintuitive, verbose,
cognitive overhead for schema if not for syntax, not type-safe, slow validation...
● Hibernate with three query languages to master with different focuses and expressivity
![Page 6: Querydsl fin jug - june 2012](https://reader033.fdocuments.net/reader033/viewer/2022050919/5475832eb4af9f9d0a8b5aff/html5/thumbnails/6.jpg)
Querydsl
● Domain model specific type-safe query language● Compile time query validation ● Instant feedback on query errors
● Compact and intuitive fluent syntax● Syntactically close to SQL● Great for dynamic query building
● Supports multiple back-ends and query languages with consistent query API● JPA/Hibernate, JDO, SQL, Lucene, Mongodb...● Once you know basics of one language, you know
basics of all SQL-like Querydsl languages
![Page 7: Querydsl fin jug - june 2012](https://reader033.fdocuments.net/reader033/viewer/2022050919/5475832eb4af9f9d0a8b5aff/html5/thumbnails/7.jpg)
Querydsl
● Autocomplete with Java IDEs● No need to remember exact syntax● No need to remember property names
● Better support for domain model refactoring● When domain changes, queries show compile
errors● Autocomplete helps fixing those
● Developed for real-life projects, e.g. Balancion and Cyclos
● Business friendly license (Apache 2.0)
![Page 8: Querydsl fin jug - june 2012](https://reader033.fdocuments.net/reader033/viewer/2022050919/5475832eb4af9f9d0a8b5aff/html5/thumbnails/8.jpg)
Querydsl
● Development started in 2007 with public releases since 2008
● Querydsl statistics:● Approximately 24 000 LOC● Test Code coverage about 75% (target 80%)● Sonar reports● FindBugs with extra annotations (@Nullable)
● Discussions about standardisations● JDO/DataNucleus started with Querydsl...
![Page 9: Querydsl fin jug - june 2012](https://reader033.fdocuments.net/reader033/viewer/2022050919/5475832eb4af9f9d0a8b5aff/html5/thumbnails/9.jpg)
Querydsl usage
● Create your variablesQPerson.person // default variablenew QPerson("myPerson") // custom variable
● Create your queryJPAQuery, HibernateQuery, SQLQueryImpl etc
● Populate your queryfrom, where, groupBy, having, orderBy
● Get the resultscount, iterate, list, uniqueResult
![Page 10: Querydsl fin jug - june 2012](https://reader033.fdocuments.net/reader033/viewer/2022050919/5475832eb4af9f9d0a8b5aff/html5/thumbnails/10.jpg)
Querydsl usage
● All expressions can be reused, immutables with caching – except BooleanBuilder and a few others
● Queries, sub queries and BooleanBuilder are stateful builder with cascading methods
![Page 11: Querydsl fin jug - june 2012](https://reader033.fdocuments.net/reader033/viewer/2022050919/5475832eb4af9f9d0a8b5aff/html5/thumbnails/11.jpg)
Overview of JPAQuery signature
fromQuery sources
innerJoin, join, leftJoin, fullJoin, onJoin elements join(source, alias) [.on(source.prop.eq(alias.prop))]
whereQuery filters, varargs for intersection (and)and(), or(), allOf(), anyOf()
![Page 12: Querydsl fin jug - june 2012](https://reader033.fdocuments.net/reader033/viewer/2022050919/5475832eb4af9f9d0a8b5aff/html5/thumbnails/12.jpg)
Overview of JPAQuery signature
groupByGroup by arguments in varargs form
havingHaving filter of the "group by” as an varags array of Predicate expressions.
orderByOrdering of the result as an varargs array of order expressions. asc() and desc() on numeric, string and other comparable expression
limit, offset, restrictPaging of the result Limit for max results and Offset for skipping rows and Restrict for defining both in one call
![Page 13: Querydsl fin jug - june 2012](https://reader033.fdocuments.net/reader033/viewer/2022050919/5475832eb4af9f9d0a8b5aff/html5/thumbnails/13.jpg)
Overview of JPAQuery signature
listGet the results as a typed List
listResultsGet the results as a typed List and total row count for paging
iterate Get the results as a typed Iterator
countGet the row count as a long
uniqueResultGet a typed single row result
![Page 14: Querydsl fin jug - june 2012](https://reader033.fdocuments.net/reader033/viewer/2022050919/5475832eb4af9f9d0a8b5aff/html5/thumbnails/14.jpg)
Simple example
QPerson person = QPerson.person;JPAQuery query = new JPAQuery(entityManager);List<Person> persons = query.from(person) .where( person.firstName.eq("John"), person.lastName.eq("Doe")) .list(person);
=>
select person from com.acme.Person personwhere person.firstName eq = ?1 and person.lastName = ?2
![Page 15: Querydsl fin jug - june 2012](https://reader033.fdocuments.net/reader033/viewer/2022050919/5475832eb4af9f9d0a8b5aff/html5/thumbnails/15.jpg)
Order
// Get persons ordered by last name and first name (desc)query.from(person)
.orderBy(person.lastName.asc(), person.firstName.desc())
.list(person);
=>
select person from Person person order by person.lastname asc, person.firstName desc
![Page 16: Querydsl fin jug - june 2012](https://reader033.fdocuments.net/reader033/viewer/2022050919/5475832eb4af9f9d0a8b5aff/html5/thumbnails/16.jpg)
Order
// Get persons ordered by women firstquery.from(person)
.orderBy(person.gender.when(Gender.FEMALE).then(0).otherwise(1).asc())
.list(person);
=>
select person from Person personorder by case person.gender = Gender.FEMALE then 0 else 1 end asc
![Page 17: Querydsl fin jug - june 2012](https://reader033.fdocuments.net/reader033/viewer/2022050919/5475832eb4af9f9d0a8b5aff/html5/thumbnails/17.jpg)
Grouping
// Get person counts grouped by last namequery.from(person) .groupBy(person.lastName) .list(person.lastName, person.count());
=>
select person.lastName, count(person) from Person persongroup by person.lastName
![Page 18: Querydsl fin jug - june 2012](https://reader033.fdocuments.net/reader033/viewer/2022050919/5475832eb4af9f9d0a8b5aff/html5/thumbnails/18.jpg)
Subqueries
//Get persons with max child countQPerson parent = new QPerson("parent");query.from(person) .where(person.children.size().eq( new JPASubQuery().from(parent)
.uniqueResult(parent.children.size().max()) )).list(person);
=>
select person from Person personwhere person.children.size() = ( select max(parent.children.size()) from Person parent)
![Page 19: Querydsl fin jug - june 2012](https://reader033.fdocuments.net/reader033/viewer/2022050919/5475832eb4af9f9d0a8b5aff/html5/thumbnails/19.jpg)
Constructor projection
// DTO class with @QueryProjection constructor annotationpublic class PersonInfo { long id; String name; @QueryProjection public PersonInfo(long id, String name) { this.id = id; this.name = name; }}
// List PersonInfo DTOs List<PersonInfo> infos = query.from(person)
.list(new QPersonInfo(person.id, person.lastName.concat(", ”).concat(person.firstName)));
![Page 20: Querydsl fin jug - june 2012](https://reader033.fdocuments.net/reader033/viewer/2022050919/5475832eb4af9f9d0a8b5aff/html5/thumbnails/20.jpg)
Tuple projection
// List ages of personsList<Tuple> tuples = query.from(person).list(new QTuple( person.lastName, person.firstName, person.yearOfBirth));
for (Tuple tuple : tuples){ // Typed access to mapped query results! String name = tuple.get(person.firstName) + " " + tuple.get(person.lastName); int age = tuple.get(person.yearOfBirth) - getCurrentYear(); System.out.println(name + " is " + age + " years");}
![Page 21: Querydsl fin jug - june 2012](https://reader033.fdocuments.net/reader033/viewer/2022050919/5475832eb4af9f9d0a8b5aff/html5/thumbnails/21.jpg)
BooleanBuilder
● Helper for building complex Boolean expressions dynamically
BooleanBuilder nameDisjunction = new BooleanBuilder();for (String name : names) { nameDisjunction.or(person.firstName.like(name)); nameDisjunction.or(person.lastName.like(name));}query.where(nameDisjunction);
![Page 22: Querydsl fin jug - june 2012](https://reader033.fdocuments.net/reader033/viewer/2022050919/5475832eb4af9f9d0a8b5aff/html5/thumbnails/22.jpg)
Update
// Set firstName of all Does to Johnlong updatedRowCount = new JPAUpdateClause(getEntityManager(), person) .set(person.firstName, "John") .where(person.lastName.eq("Doe")) .execute();
=>
update Person personset person.firstName = ?1where person.lastName = ?2
![Page 23: Querydsl fin jug - june 2012](https://reader033.fdocuments.net/reader033/viewer/2022050919/5475832eb4af9f9d0a8b5aff/html5/thumbnails/23.jpg)
Delete
// Delete all John Doeslong updatedRowCount = new JPADeleteClause(getEntityManager(), person) .where(person.lastName.eq("Doe"), person.firstName.eq("John")) .execute();
=>
delete Person personwhere person.lastName = ?1 and person.firstName = ?2
![Page 24: Querydsl fin jug - june 2012](https://reader033.fdocuments.net/reader033/viewer/2022050919/5475832eb4af9f9d0a8b5aff/html5/thumbnails/24.jpg)
Querydsl extensions
● Customize the code generation● @QueryType(PropertyType.NONE)
● Non searchable● @QueryType(PropertyType.SIMPLE)
● Equality comparisons only (eq, ne, in)● Custom query classes
● Extend abstract super classes and preserve fluent API
● Custom expressions● Static delegate methods with @QueryDelegate● Template expressions for e.g. custom SQL
functions
![Page 25: Querydsl fin jug - june 2012](https://reader033.fdocuments.net/reader033/viewer/2022050919/5475832eb4af9f9d0a8b5aff/html5/thumbnails/25.jpg)
Querydsl extensions
● Query serialization can be customized● Works for JPA, JDO and SQL● SQL dialects● Overriding default templates (e.g.
String#startsWith with like or regexp or...)● Expression DSL can be replaced
● E.g. Querydsl for Scala● Custom back-ends
● Lucene (10 classes) + Mongodb (6 classes)
![Page 26: Querydsl fin jug - june 2012](https://reader033.fdocuments.net/reader033/viewer/2022050919/5475832eb4af9f9d0a8b5aff/html5/thumbnails/26.jpg)
Delegate methods
public class MyQueryExtensions { @QueryDelegate(Date.class) public static NumberExpression<Integer> yearAndMonth(DateTimePath<Date> date) { return date.year().multiply(100).add(date.month()); }}
=>
package ext.java.util;...public class QDate extends DateTimePath<java.util.Date> {... public NumberExpression<Integer> yearAndMonth() { return MyQueryExtensions.yearAndMonth(this); }}
![Page 27: Querydsl fin jug - june 2012](https://reader033.fdocuments.net/reader033/viewer/2022050919/5475832eb4af9f9d0a8b5aff/html5/thumbnails/27.jpg)
Template expressions
// ilike query.from(person).where(BooleanTemplate.create("{0} ilike {1}”, person.lastName, ConstantImpl.create("P%"))).list(person);
=>
select person from Person personwhere person.lastName ilike ?1
![Page 28: Querydsl fin jug - june 2012](https://reader033.fdocuments.net/reader033/viewer/2022050919/5475832eb4af9f9d0a8b5aff/html5/thumbnails/28.jpg)
Custom query classes
public class PersonQuery extends AbstractJPAQuery<PersonQuery> { final QPerson person = QPerson.person; public PersonQuery(EntityManager em) { super(em); from(person); } public PersonQuery nameMatches(String name) { return where(person.firstName.like(name) .or(person.lastName.like(name))); }}
![Page 29: Querydsl fin jug - june 2012](https://reader033.fdocuments.net/reader033/viewer/2022050919/5475832eb4af9f9d0a8b5aff/html5/thumbnails/29.jpg)
JPA 2.0 Criteria vs Querydsl
● JPA 2 Criteria is the standard for type-safe queries in JPA, but Querydsl is in our opinion superior in many ways● Easier and less verbose syntax● Customizable● Supports multiple back-ends – not just JPA
● JPA has a difficult to use static query-model● Verbose property paths● Operations via builder object
● Inverse order: “equals property value” vs. “property equals value”● Broken flow
![Page 30: Querydsl fin jug - june 2012](https://reader033.fdocuments.net/reader033/viewer/2022050919/5475832eb4af9f9d0a8b5aff/html5/thumbnails/30.jpg)
Criteria example
// All possible pairs of single males and femalesCriteriaQuery<Person> query = builder.createQuery(Person.class);Root<Person> men = query.from( Person.class );Root<Person> women = query.from( Person.class );Predicate menRestriction = builder.and( builder.equal( men.get( Person_.gender ), Gender.MALE ), builder.equal( men.get( Person_.relationshipStatus ), RelationshipStatus.SINGLE ));Predicate womenRestriction = builder.and( builder.equal( women.get( Person_.gender ), Gender.FEMALE ), builder.equal( women.get( Person_.relationshipStatus ), RelationshipStatus.SINGLE ));query.where( builder.and( menRestriction, womenRestriction ) );
![Page 31: Querydsl fin jug - june 2012](https://reader033.fdocuments.net/reader033/viewer/2022050919/5475832eb4af9f9d0a8b5aff/html5/thumbnails/31.jpg)
Querydsl example
// All possible pairs of single males and femalesJPAQuery query = new JPAQuery(entityManager);QPerson men = new QPerson("men");QPerson women = new QPerson("women");query.from(men, women).where(
men.gender.eq(Gender.MALE),men.relationshipStatus.eq(RelationshipStatus.SINGLE),women.gender.eq(Gender.FEMALE),women.relationshipStatus.eq(RelationshipStatus.SINGLE));
![Page 32: Querydsl fin jug - june 2012](https://reader033.fdocuments.net/reader033/viewer/2022050919/5475832eb4af9f9d0a8b5aff/html5/thumbnails/32.jpg)
SQL
● Pretty similar to JPA/Hibernate● No deep paths over relations though● No implicit joins
SQLTemplates templates = new MySQLTemplates();...
SQLQuery query = new SQLQueryImpl(connection, templates);
query.from(person);query.innerJoin(parent).on(parent.id.eq(person.parent.id));
● Shortcut for joins with foreign keys
query.innerJoin(person.parentFK, parent);
![Page 33: Querydsl fin jug - june 2012](https://reader033.fdocuments.net/reader033/viewer/2022050919/5475832eb4af9f9d0a8b5aff/html5/thumbnails/33.jpg)
SQL
● Maven plugin for generating query model● Support for special SQL constructs and extensions
● Databases supported include● MySQL● PostgreSQL● Oracle● MS SQL Server● H2● HSQLDB● Derby● SQLite● CUBRID
![Page 34: Querydsl fin jug - june 2012](https://reader033.fdocuments.net/reader033/viewer/2022050919/5475832eb4af9f9d0a8b5aff/html5/thumbnails/34.jpg)
SQL extensions
● Sub class of AbstractSQLQuery● e.g. OracleQuery with connectByPrior
● Template expressions● Direct addition of “flags”
SQLInsertClause insert = new SQLInsertClause(connection, templates, person);insert.addFlag(Position.START_OVERRIDE, "replace into ");
![Page 35: Querydsl fin jug - june 2012](https://reader033.fdocuments.net/reader033/viewer/2022050919/5475832eb4af9f9d0a8b5aff/html5/thumbnails/35.jpg)
JPA/Hibernate Maven Integration
<build><plugins><plugin> <groupId>com.mysema.maven</groupId> <artifactId>maven-apt-plugin</artifactId> <version>1.0.3</version> <executions> <execution> <goals><goal>process</goal></goals> <configuration> <outputDirectory>target/generated-sources/java</outputDirectory> <processor>com.mysema.query.apt.jpa.JPAAnnotationProcessor</processor> </configuration> </execution> </executions></plugin></plugins></build>
![Page 36: Querydsl fin jug - june 2012](https://reader033.fdocuments.net/reader033/viewer/2022050919/5475832eb4af9f9d0a8b5aff/html5/thumbnails/36.jpg)
SQL Maven Integration
<build><plugins><plugin> <groupId>com.mysema.querydsl</groupId> <artifactId>querydsl-maven-plugin</artifactId> <version>${querydsl.version}</version> <executions><execution> <goals><goal>export</goal></goals> </execution></executions> <configuration> <jdbcDriver>org.apache.derby.jdbc.EmbeddedDriver</jdbcDriver> <jdbcUrl>jdbc:derby:target/demoDB;create=true</jdbcUrl> <!—- optional elements : namePrefix, jdbcUser, jdbcPassword, schemaPattern, tableNamePattern --> <packageName>com.myproject.domain</packageName> <targetFolder>${project.basedir}/target/generated-sources/java</targetFolder> </configuration> <dependencies><dependency> <!—- jdbc driver dependency --> <groupId>org.apache.derby</groupId> <artifactId>derby</artifactId> <version>${derby.version}</version> </dependency></dependencies></plugin></plugins></build>
![Page 37: Querydsl fin jug - june 2012](https://reader033.fdocuments.net/reader033/viewer/2022050919/5475832eb4af9f9d0a8b5aff/html5/thumbnails/37.jpg)
What does Mysema offer for Querydsl?
● Free public support● GitHub Issues● Querydsl Google Group● Mysema Blog
● Consulting services● User support● Custom extensions and integration● Training
![Page 38: Querydsl fin jug - june 2012](https://reader033.fdocuments.net/reader033/viewer/2022050919/5475832eb4af9f9d0a8b5aff/html5/thumbnails/38.jpg)
Querydsl support from other companies
● VMware uses Querydsl in Spring Data for the following backends● JPA● SQL/JDBC● MongoDB● Neo4j
● Spring Data is a good option if you want to use repositories in Spring with Querydsl support
![Page 39: Querydsl fin jug - june 2012](https://reader033.fdocuments.net/reader033/viewer/2022050919/5475832eb4af9f9d0a8b5aff/html5/thumbnails/39.jpg)
Questions?
![Page 40: Querydsl fin jug - june 2012](https://reader033.fdocuments.net/reader033/viewer/2022050919/5475832eb4af9f9d0a8b5aff/html5/thumbnails/40.jpg)
Thanks!
Timo Westkämper@timowest
www.querydsl.comwww.mysema.com