Spring Data JPA

Pardhu Guttikonda
4 min readNov 27, 2022

--

Spring Data JPA provides repository support for the Jakarta Persistence API (JPA).

Photo by Markus Spiske on Unsplash

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>
Photo by Tracy Adams on Unsplash

🙌🏻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);
}
Photo by Aron Visuals on Unsplash

🧞‍♂️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);
Photo by Sai Kiran Anagani on Unsplash

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

Photo by Wilhelm Gunkel on Unsplash

--

--