7.6.1. The jOOQ DSL
jOOQ comes with its own DSL (for Domain Specific Language) that emulates SQL in Java. It allows you to write SQL statements almost as though Java actually supported them. Its effect is similar to what .NET in C# does with LINQ to SQL.
jOOQ uses an informal BNF notation modelling a unified SQL dialect suitable for most database engines. Unlike other, simpler frameworks that use the Fluent API or the chain method, the jOOQ-based BNF interface does not permit bad query syntax.
A simple SQL query:
SELECT *
FROM author a
JOIN book b ON a.id = b.author_id
WHERE a.year_of_birth > 1920
AND a.first_name = 'Paulo'
ORDER BY b.title
In jOOQ it looks like this:
Result<Record> result =
dsl.select()
.from(AUTHOR.as("a"))
.join(BOOK.as("b")).on(a.ID.equal(b.AUTHOR_ID))
.where(a.YEAR_OF_BIRTH.greaterThan(1920)
.and(a.FIRST_NAME.equal("Paulo")))
.orderBy(b.TITLE)
.fetch();
The AUTHOR
and BOOK
classes describing the corresponding tables must be generated beforehand. The process of generating jOOQ classes according to the specified database schema was described earlier.
We specified table aliases for the AUTHOR
and BOOK
tables using the AS
clause. Here is the same query in DSL without aliases:
Result<Record> result =
dsl.select()
.from(AUTHOR)
.join(BOOK).on(AUTHOR.ID.equal(BOOK.AUTHOR_ID))
.where(AUTHOR.YEAR_OF_BIRTH.greaterThan(1920)
.and(AUTHOR.FIRST_NAME.equal("Paulo")))
.orderBy(BOOK.TITLE)
.fetch();
Now we take a more complex query with aggregate functions and grouping:
SELECT AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME, COUNT(*)
FROM AUTHOR
JOIN BOOK ON AUTHOR.ID = BOOK.AUTHOR_ID
WHERE BOOK.LANGUAGE = 'DE'
AND BOOK.PUBLISHED > '2008-01-01'
GROUP BY AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME
HAVING COUNT(*) > 5
ORDER BY AUTHOR.LAST_NAME ASC NULLS FIRST
OFFSET 1 ROWS
FETCH FIRST 2 ROWS ONLY
In jOOQ:
dsl.select(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME, count())
.from(AUTHOR)
.join(BOOK).on(BOOK.AUTHOR_ID.equal(AUTHOR.ID))
.where(BOOK.LANGUAGE.equal("DE"))
.and(BOOK.PUBLISHED.greaterThan("2008-01-01"))
.groupBy(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)
.having(count().greaterThan(5))
.orderBy(AUTHOR.LAST_NAME.asc().nullsFirst())
.limit(2)
.offset(1)
.fetch();
‘Dialect’ in the jOOQ context represents not just the SQL dialect of the database but also the major version number of the database engine. The field ‘limit’, limiting the number of records returned, will be generated according to the SQL syntax available to the database engine. The example above used |
You can build a query in parts. This will allow you to change it dynamically, to change the sort order or to add additional filter conditions.
SelectFinalStep<?> select
= dsl.select()
.from(PRODUCT);
SelectQuery<?> query = select.getQuery();
switch (searchOper) {
case "eq":
query.addConditions(PRODUCT.NAME.eq(searchString));
break;
case "bw":
query.addConditions(PRODUCT.NAME.startsWith(searchString));
break;
case "cn":
query.addConditions(PRODUCT.NAME.contains(searchString));
break;
}
switch (sOrd) {
case "asc":
query.addOrderBy(PRODUCT.NAME.asc());
break;
case "desc":
query.addOrderBy(PRODUCT.NAME.desc());
break;
}
return query.fetchMaps();