Spring Data JPA
click here to read this in medium
Spring Data JPA provides repository support for the Jakarta Persistence API (JPA).
Spring Data JPA provides repository support for the Jakarta Persistence API(JPA).
It is used to improve the implementation of data access layers by reducing the efforts to the amount that’s actually needed.
⛹️♂️Dependencies
The below dependency needs to be in the build.gradle file.
<dependencies>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
</dependency>
<dependencies>
🙌🏻Basic concepts
In general, We use CrudRepository for the CREATE, READ, UPDATE and DELETE operations and PagingAndSortingRepository for pagination and sort records. In JpaRepository provides JPA related methods such as flushing the persistence context and delete records in a batch. So JpaRepository inherities both the CrudRepository and PagingAndSorting.Addtional to that it gives a different methods to filter, save and query from the repository.
👉Creating Repository Interface:
So in this interface we can give the method names and spring will take care of logic in it.
Note:- All the below example need to be inside these kind of interface which extends JpaRepository.
@Repository
public interface ProductRepository extends JpaRepository<Product, Long> {
Product findByName(String productName);
}
🧞♂️Methods we can use in JPA
CURD Operations and PagingAndSorting Operations:
<S extends T> S save(S entity); //-->save entity to DB
Optional<T> findById(ID primaryKey); //-->find entity from DB
Iterable<T> findAll();//-->get ALL
long count();//--> get count of entities
void delete(T entity);// --> delete an entity
boolean existsById(ID primaryKey);// --> is exist by ID
Iterable<T> findAll(Sort sort);
Page<T> findAll(Pageable pageable);//example below
repository.findAll(PageRequest.of(1, 20));
long countByLastname(String lastname); // we can use any field name in place of Lastname
long deleteByLastname(String lastname);
List<User> removeByLastname(String lastname);
Query Methods:
List<Person> findByLastname(String lastname);
Optional<T> findById(ID id);
User findByEmailAddress(EmailAddress emailAddress);
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);
In the above example we can create the methods in interface as we need using the Distinct flag, Ignore Case and order BY. Also, we can use And, Or to pass multiple parameters to the method.
Property Expressions:
If you have a case where you want to get a entity based on nested property for example we want to get list of People who has a given zipcode, Zipcode is present inside Address. So this case we can use the below code.
List<Person> findByAddressZipCode(ZipCode zipCode);//better way
List<Person> findByAddress_ZipCode(ZipCode zipCode);//also correct
Special Parameter handling:
Page<User> findByLastname(String lastname, Pageable pageable);
Slice<User> findByLastname(String lastname, Pageable pageable);
List<User> findByLastname(String lastname, Sort sort);
List<User> findByLastname(String lastname, Pageable pageable);
//SORT example
Sort sort = Sort.by("firstname").ascending()
.and(Sort.by("lastname").descending());
TypedSort<Person> person = Sort.sort(Person.class);
Sort sort = person.by(Person::getFirstname).ascending()
.and(person.by(Person::getLastname).descending());
Limiting Query Results:
User findFirstByOrderByLastnameAsc();
User findTopByOrderByAgeDesc();
Page<User> queryFirst10ByLastname(String lastname, Pageable pageable);
Slice<User> findTop3ByLastname(String lastname, Pageable pageable);
List<User> findFirst10ByLastname(String lastname, Sort sort);
List<User> findTop10ByLastname(String lastname, Pageable pageable);
Streamble:
Now I came across a point where we need to get entities based on condition if name contains two letters in it I need them.
interface PersonRepository extends Repository<Person, Long> {
Streamable<Person> findByFirstnameContaining(String firstname);
Streamable<Person> findByLastnameContaining(String lastname);
}
Streamable<Person> result = repository.findByFirstnameContaining("av")
.and(repository.findByLastnameContaining("ea"));
Streaming Query Results:
We can run the Query as below.
@Query("select u from User u")
Stream<User> findAllByCustomQueryAndStream();
Stream<User> readAllByFirstnameNotNull();
@Query("select u from User u")
Stream<User> streamAllPaged(Pageable pageable);
Asynchronous Query Results:
Asynchronous way to run Queries.
@Async
Future<User> findByFirstname(String firstname);
@Async
CompletableFuture<User> findOneByFirstname(String firstname);
//useage
CompletableFuture<User> user= findByFirstname("Macintosh");
user(System.out::println);
Referances:
docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.core-concepts