diff --git a/documentation/src/main/asciidoc/repositories/Pagination.adoc b/documentation/src/main/asciidoc/repositories/Pagination.adoc index c801c06ee06e..33555767110c 100644 --- a/documentation/src/main/asciidoc/repositories/Pagination.adoc +++ b/documentation/src/main/asciidoc/repositories/Pagination.adoc @@ -8,6 +8,7 @@ An <> or <> query method may have Before we see this, let's see how we can refer to a field of an entity in a completely typesafe way. +[[data-static-metamodel]] === The static metamodel You might already be familiar with the Jakarta Persistence static metamodel. @@ -59,6 +60,7 @@ This example looks superficially more typesafe. But since Hibernate Data Repositories already validates the content of the `@OrderBy` annotation at compile time, it's not really better. ==== +[[dynamic-sorting]] === Dynamic sorting Dynamic sorting criteria are expressed using the types `Sort` and `Order`: @@ -100,7 +102,7 @@ The method might now be called like this: var books = library.books(pattern, year, Order.of(_Book.title.ascIgnoreCase(), - _Book.isbn.asc()); + _Book.isbn.asc())); ---- Dynamic sorting criteria may be combined with static criteria. @@ -115,6 +117,7 @@ List books(@Pattern String title, Year yearPublished, We're not convinced this is very useful in practice. +[[limits]] === Limits A `Limit` is the simplest way to express a subrange of query results. @@ -141,6 +144,7 @@ var books = A more sophisticated approach is provided by `PageRequest`. +[[offset-based-pagination]] === Offset-based pagination A `PageRequest` is superficially similar to a `Limit`, except that it's specified in terms of: @@ -218,6 +222,7 @@ We'll refer to this as _offset-based pagination_. A problem with this approach is that it's quite vulnerable to missed or duplicate results when the database is modified between page requests. Therefore, Jakarta Data offers an alternative solution, which we'll call _key-based pagination_. +[[key-based-pagination]] === Key-based pagination In key-based pagination, the query results must be totally ordered by a unique key of the result set. @@ -241,7 +246,7 @@ The difference is that we must declare our repository method to return `Cursored @OrderBy("title") @OrderBy("isbn") CursoredPage books(@Pattern String title, Year yearPublished, - PageRequest pageRequest); + PageRequest pageRequest); ---- On the other hand, with key-based pagination, Hibernate must do some work under the covers rewriting our query. @@ -258,6 +263,63 @@ Direct API support for key-based pagination originated in the work of Hibernate It was adopted from there by the Jakarta Data specification, and is now even available in Hibernate ORM via the link:{doc-javadoc-url}org/hibernate/query/KeyedPage.html[`KeyedPage`]/link:{doc-javadoc-url}org/hibernate/query/KeyedResultList.html[`KeyedResultList`] API. **** +[[dynamic-restrictions]] +=== Dynamic restrictions + +Jakarta Data 1.0 does not include an API for programmatically specifying restrictions, but for now we may use the native link:{doc-javadoc-url}org/hibernate/query/restriction/Restriction.html[`Restriction`] API in Hibernate 7. + +[NOTE] +==== +Restrictions will be standardized by Jakarta Data 1.1. +==== + +Hibernate, an atomic `Restriction` is formed from: + +- a reference to a JPA `SingularAttribute`, usually obtained via the _Jakarta Persistence_ (not Jakarta Data) static metamodel, together with +- a `Range` of allowed values for that attribute. + +A query method may have a parameter of type `Restriction`, for example: + +[source,java] +---- +@Find +List books(Restriction restriction, + Order order); +---- + +This method would be called like this: + +[source,java] +---- +var books = + library.books(Restriction.contains(Book_.title, "Hibernate"), + Order.of(_Book.title.ascIgnoreCase(), + _Book.isbn.asc())); +---- + +Notice the mix of metamodels here: `Book_` is the Persistence metamodel, and `_Book` is the Data metamodel. + +It's even possible to directly use a link:{doc-javadoc-url}org/hibernate/query/range/Range.html[`Range`] to restrict a given property or field of an entity: + +[source,java] +---- +@Find +List books(Range title, Range yearPublished, + Order order); +---- + +There are various kinds of `Range`, including lists, patterns, and intervals: + +[source,java] +---- +var books = + library.books(Range.prefix("Hibernate"), + Range.closed(Year.of(2000), Year.of(2009)), + Order.of(_Book.title.ascIgnoreCase(), + _Book.isbn.asc())); +---- + +[[advanced-query-control]] === Advanced control over querying For more advanced usage, an automatic or annotated query method may be declared to return `jakarta.persistence.Query`, `jakarta.persistence.TypedQuery`, link:{doc-javadoc-url}org/hibernate/query/Query.html[`org.hibernate.query.Query`], or link:{doc-javadoc-url}org/hibernate/query/SelectionQuery.html[`org.hibernate.query.SelectionQuery`]. @@ -269,11 +331,11 @@ SelectionQuery booksQuery(@Pattern String title, Year yearPublished); default List booksQuery(String title, Year yearPublished) { return books(title, yearPublished) - .enableFetchProfile(_Book.PROFILE_WITH_AUTHORS); + .enableFetchProfile(_Book.PROFILE_WITH_AUTHORS) .setReadOnly(true) .setTimeout(QUERY_TIMEOUT) .getResultList(); } ---- -This allows for direct control over query execution, without loss of typesafety. \ No newline at end of file +This allows for direct control over query execution, without loss of type safety. \ No newline at end of file diff --git a/documentation/src/main/asciidoc/repositories/Repositories.adoc b/documentation/src/main/asciidoc/repositories/Repositories.adoc index 8c8f71bd39a8..50c703e1d0db 100644 --- a/documentation/src/main/asciidoc/repositories/Repositories.adoc +++ b/documentation/src/main/asciidoc/repositories/Repositories.adoc @@ -131,6 +131,7 @@ interface Library { This is our first example of a repository. +[[repository-interfaces]] === Repository interfaces A _repository interface_ is an interface written by you, the application programmer, and annotated `@Repository`. @@ -165,6 +166,7 @@ We'll discuss each of these kinds of method soon. But first we need to ask a more basic question: how are persistence operations organized into repositories, and how do repository interfaces relate to entity types? The--perhaps surprising--answer is: it's completely up to you. +[[organizing-repository-operations]] === Organizing persistence operations Jakarta Data lets you freely assign persistence operations to repositories according to your own preference. @@ -536,6 +538,7 @@ List booksByTitle(String pattern); Unfortunately, native SQL queries cannot be validated at compile time, so if there's anything wrong with our SQL, we won't find out until we run our program. +[[by-and-param]] === `@By` and `@Param` Query methods match method parameters to entity fields or query parameters by name.