Spring Data JPA
Suppose you have the Book entity using Spring Boot Data JPA.
@Entity
class Book(
@Id
val id: Int,
val title: String,
val author: String
)
And you need to filter by the author and the title. You can create an instance of the Criteria class and define the filters with the values.
val criteria = Criteria(
filters = listOf(
Filter("title", "Kotlin", FilterOperator.CONTAINS),
Filter("author", "Svetlana Isakova", FilterOperator.EQUALS)
)
)
This instance of the Criteria class will filter by books with title that contains the "Kotlin" word and by the author "Svetlana Isakova"
To perform a query using this criteria you will need to implement on our JPA Repository the JpaSpecificationExecutor<T>
interface for allow to execute queries through the spring Specification<T>
interface.
@Repository
interface BookRepository : CrudRepository<Book, Long>, JpaSpecificationExecutor<Book>
Now we can autowire BookRepository
and execute the query with our criteria
instance.
@Autowired
lateinit var bookRepository: BookRepository
val adapter = CriteriaJPASpecificationAdapter()
val result = adapter.apply(criteria, bookRepository)
// The result variable contains the collection of Book instances
How to add joins on criteria
Now imagine you have the BookAuthor
entity that is related with the Book
entity with a OneToMany
relationship
@Entity
class Book(
//...
@ManyToOne
@JoinColumn(name = "author_id")
var author: BookAuthor,
)
@Entity
class BookAuthor(
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
var id: Long? = null,
var name: String,
val birthDate: Instant,
@OneToMany(mappedBy = "author")
val books: MutableList<Book> = mutableListOf(),
)
We can add a join from the Book
entity to BookAuthor
entity for create a criteria that filters by the author name. For this we need to create a join map.
The join map is simple, you need to define a Map
with a key that is the relation name and as value the join definition.
mapOf(
"<relation name>" to join<Book, BookAuthor>("<property that has the relation on Book entity>", JoinType.INNER) // The join definition
)
As the last example we need to call the adapt
method from CriteriaJPASpecificationAdapter
and add the join map on the adapt
method
@Autowired
lateinit var bookRepository: BookRepository
val criteria = Criteria(
filters = listOf(
// We use the relation notation as filter name, first the relation name defined
// as the key on the join map and the related field name before the "."
// NOTE: the related field name is a property name of BookAuthor entity
Filter("author.name", "Svetlana Isakova", FilterOperator.EQUALS)
)
)
val adapter = CriteriaJPASpecificationAdapter()
val result = adapter.apply(criteria, bookRepository) {
mapOf(
"author" to join<Book, BookAuthor>("author", JoinType.INNER)
)
}
// The result variable contains the collection of filtered Book instances
If you have a FieldMap
you can add it into the CriteriaJPASpecificationAdapter
constructor.
val fieldMap = mapOf(
// this will indicate the field author_name points to author.name related field
"author_name" to "author.name"
)
// ...
val adapter = CriteriaJPASpecificationAdapter(fieldMap)
val result = adapter.apply(criteria, bookRepository)
Last updated