JPA
@Configuration
@EnableJpaRepositories
@EntityScan
EntityManagerBean – is automatically configured, interacts with persistent context
PlatformTransactionManager – defines basic operation from transactional data access management.
There are 3 main types of repositoriesL
- JpaRepository
- CrudRepository
- PagingAndSortingRepository
Derived query method: subject+predicate
- findBy
- countBy
- deleteBy
- queryBy
interface PersonRepository extends Repository<Person, Long> {
List<Person> findByEmailAddressAndLastname(EmailAddress emailAddress, String lastname);
// Enables the distinct flag for the query
List<Person> findDistinctPeopleByLastnameOrFirstname(String lastname, String firstname);
List<Person> findPeopleDistinctByLastnameOrFirstname(String lastname, String firstname);
// Enabling ignoring case for an individual property
List<Person> findByLastnameIgnoreCase(String lastname);
// Enabling ignoring case for all suitable properties
List<Person> findByLastnameAndFirstnameAllIgnoreCase(String lastname, String firstname);
// Enabling static ORDER BY for a query
List<Person> findByLastnameOrderByFirstnameAsc(String lastname);
List<Person> findByLastnameOrderByFirstnameDesc(String lastname);
}
Keyword | Sample | JPQL snippet |
---|---|---|
Distinct | findDistinctByLastnameAndFirstname | select distinct … where x.lastname = ?1 and x.firstname = ?2 |
And | findByLastnameAndFirstname | … where x.lastname = ?1 and x.firstname = ?2 |
Or | findByLastnameOrFirstname | … where x.lastname = ?1 or x.firstname = ?2 |
Is , Equals | findByFirstname ,findByFirstnameIs , findByFirstnameEquals | … where x.firstname = ?1 |
Between | findByStartDateBetween | … where x.startDate between ?1 and ?2 |
LessThan | findByAgeLessThan | … where x.age < ?1 |
LessThanEqual | findByAgeLessThanEqual | … where x.age <= ?1 |
GreaterThan | findByAgeGreaterThan | … where x.age > ?1 |
GreaterThanEqual | findByAgeGreaterThanEqual | … where x.age >= ?1 |
After | findByStartDateAfter | … where x.startDate > ?1 |
Before | findByStartDateBefore | … where x.startDate < ?1 |
IsNull , Null | findByAge(Is)Null | … where x.age is null |
IsNotNull , NotNull | findByAge(Is)NotNull | … where x.age not null |
Like | findByFirstnameLike | … where x.firstname like ?1 |
NotLike | findByFirstnameNotLike | … where x.firstname not like ?1 |
StartingWith | findByFirstnameStartingWith | … where x.firstname like ?1 (parameter bound with appended % ) |
EndingWith | findByFirstnameEndingWith | … where x.firstname like ?1 (parameter bound with prepended % ) |
Containing | findByFirstnameContaining | … where x.firstname like ?1 (parameter bound wrapped in % ) |
OrderBy | findByAgeOrderByLastnameDesc | … where x.age = ?1 order by x.lastname desc |
Not | findByLastnameNot | … where x.lastname <> ?1 |
In | findByAgeIn(Collection<Age> ages) | … where x.age in ?1 |
NotIn | findByAgeNotIn(Collection<Age> ages) | … where x.age not in ?1 |
True | findByActiveTrue() | … where x.active = true |
False | findByActiveFalse() | … where x.active = false |
IgnoreCase | findByFirstnameIgnoreCase | … where UPPER(x.firstname) = UPPER(?1) |
Repository
- save() – method will detect id is null and create a new instance if needed.
- saveAll()
- cascadeall also works with create
All persistent and delete operations require to be executed with a transaction in order for changes to be persisted.
Custom query methods need to be annotated with @Transactional.
@Transactional(readOnly = true)
For read operations, the transaction configuration readOnly flag is set to true
@DataJpaTest
All tests annotated with @DataJpaTest will become transactional but tranasactions are rolleck back at the end of every test.
TestEntityManager
TestEntityManager can be inject in tests
Alternative to EntityManager for use in JPA tests. Provides a subset of EntityManager methods that are useful for tests as well as helper methods for common testing tasks such as persist/flush/find.
Spring Data JPA – @Modifying Annotation
@Modifying annotation in Spring Data JPA allows modification queries such as update and delete and enhances the capabilities of the @Query annotation. It enables data transformation actions beyond simple data retrieval, ensuring transaction integrity and improving performance.
The @Modifying annotation is used to enhance the @Query annotation so that we can not only execute the SELECT queries, but also INSERT, UPDATE, DELETE, and even DDL queries that modify the structure of the underlying database schema using Spring Data JPA
Benefits of @Modifying Annotation
@Modifying annotation is used when you want to execute modifying queries, such as updates or deletes. This annotation is necessary because, by default, Spring Data JPA repository methods are considered read-only and are optimized for querying data, not modifying it.
- Improved Performance: Improves performance by allowing changing queries to be executed.
- Transactional Integrity: Ensures transaction integrity while performing data changes.
- Support for native queries: Enables native queries for data transformation.
- Automatic Flush and Clear: Supports automatic flushing and clearing of durability references.
Queries
@Query("select p from Project p when p.code like %exp%")
List<Project> findByCode(@Param("exp") String code)
native query
@Query(native=true, value="select * from project limit 1")
Optional<Project> findSingleProject
Query("select p from Project p where p.name=?1 and p.description=?2")
List<Project> findXXX(String name, String desc)
@Query("select u from User u where u.firstname = :firstname or u.lastname = :lastname")
User findByLastnameOrFirstname(@Param("lastname") String lastname,
@Param("firstname") String firstname);
By default annotated queries return the number of affected entities from the operation.
Spring data does not support sort params in native queries.
Named queries – are predefined static queries with an unique name and query string.
@NamedQuery(name="myNamedQuery", query="...")
<<<<
@Entity
public class Project {
//same method in repo
//
OR
entityManager.createNamedQuery("myNamedQuery",...)...
Pagination and sorting
public interface PagingAndSortingRepository<>
extends Repository<> {
Iterable<> findAll(Sort);
Page<T> findAll(Pageable)
}
///
Pageable x = PageRequest.of(pageNumber,pageSize,sort)
Sort s = Sort.by(Sort.Direction.ASC,"field")
Example of methods:
// findAllByOrderByDueDateDesc()
// findFirst5ByOrderByStatusDesc