Open In App

Derived Query Methods in Spring Data JPA Repositories

Last Updated : 20 Aug, 2024
Comments
Improve
Suggest changes
Like Article
Like
Report

Spring Data JPA helps manage database operations in Java applications with ease. One powerful feature is derived query methods, which let you perform common database queries by just naming the method. This way, you don’t have to write complex SQL or JPQL queries manually. Instead, you can use simple method names to search, sort, and filter your data, making your code cleaner and easier to maintain.

Benefits of Spring Data JPA Repositories

  • Encapsulation: Repository interfaces isolate data access logic for each entity.
  • Maintenance: Changes to data access methods are confined to specific repository interfaces.
  • Type Safety: Interfaces provide strong typing for entity operations.
  • Modularity and Clarity: Each repository focuses on a single entity type, ensuring that repository methods are concise and relevant.

Implementation of Derived Query Methods

Here is the step-by-step process for derived query methods in Spring Data JPA Repositories:

Step 1: Define the Entity

Create an entity class to represent the database table. For example, the AppUser entity:

Java
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import java.time.ZonedDateTime;

@Table(name = "app_users")
@Entity
public class AppUser {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer userId;
    
    private String fullName;
    private Integer userAge;
    private ZonedDateTime dateOfBirth;
    private Boolean isActive;

    // Constructors
    public AppUser() {}

    public AppUser(String fullName, Integer userAge, ZonedDateTime dateOfBirth, Boolean isActive) {
        this.fullName = fullName;
        this.userAge = userAge;
        this.dateOfBirth = dateOfBirth;
        this.isActive = isActive;
    }

    // Getters and Setters
    public Integer getUserId() { 
      return userId; 
    }
    public void setUserId(Integer userId) { 
      this.userId = userId; 
    }
    public String getFullName() { 
      return fullName; 
    }
    public void setFullName(String fullName) { 
      this.fullName = fullName; 
    }
    public Integer getUserAge() { 
      return userAge; 
    }
    public void setUserAge(Integer userAge) { 
      this.userAge = userAge; 
    }
    public ZonedDateTime getDateOfBirth() { 
      return dateOfBirth; 
    }
    public void setDateOfBirth(ZonedDateTime dateOfBirth) { 
      this.dateOfBirth = dateOfBirth; 
    }
    public Boolean getIsActive() { 
      return isActive; 
    }
    public void setIsActive(Boolean isActive) { 
      this.isActive = isActive; 
    }
}

Explanation:

  • @GeneratedValue(strategy = GenerationType.IDENTITY) indicates that the database will generate the primary key value automatically. Because of the IDENTITY strategy, each time a new AppUser is inserted, the database will create a unique value for userId.
  • private Boolean isActive returns the value of whether the user is currently active. The value of this field is Boolean.
  • A JPA entity that corresponds to the database's app_users table is the AppUser class.

Step 2: Derived Queries with Multiple Parameters

Next, you can utilize this query by passing the first name you wish to search for to the findByFirstName() method when you call an instance of the AuthorRepository.

Java
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@SpringBootTest(classes = MyApplication.class)
public class AuthorRepositoryTest {

    @Autowired
    private AuthorRepository authorRepo;

    @Test
    @Transactional
    public void shouldFindAuthorsByFirstName() {
        List<Author> authors = authorRepo.findByFirstName("Thorben");
        // Add assertions or further actions to validate the result
    }
}

Explanation:

  • @SpringBootTest(classes = MyApplication.class, this annotation instructs Spring Boot to generate an application context for the test. The test may now execute in a fully initialized Spring environment thanks to it.
  • @Autowired private AuthorRepository authorRepo inserts an instance of AuthorRepository into the test class with the command "AuthorRepository authorRepo;" This enables you to communicate with the database in your test using the repository ways.

Step 3: Define the Repository

Create a repository interface extending JpaRepository to perform CRUD operations and custom queries:

Java
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    
    // Find users by name and order them by name (default ordering, usually ascending)
    List<User> findByNameOrderByName(String name);
    
    // Find users by name and order them explicitly in ascending order
    List<User> findByNameOrderByNameAsc(String name);
}

Explanation:

  • public interface UserRepository extends JpaRepository<User, Long>, it comes to User entities—where User is the entity type and Long is the type of its main key—it permits both CRUD operations and additional custom queries.
  • Sort the results according to the name field. If you use OrderByName without specifically setting the order, Spring Data JPA arranges the results in ascending order by default.

Step 4: Add Service Layer

We can build a service layer to communicate with the repository. This layer manages interactions between the controller and repository and may include business logic.

Java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    public List<User> getUsersByNameOrdered(String name) {
        return userRepository.findByNameOrderByName(name);
    }

    public List<User> getUsersByNameOrderedAsc(String name) {
        return userRepository.findByNameOrderByNameAsc(name);
    }
}

Step 5: Use Controller Layer

Make a controller utilizing the service layer to process HTTP requests and return responses.

Java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;

@RestController
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping("/users/name/{name}")
    public List<User> getUsersByNameOrdered(@PathVariable String name) {
        return userService.getUsersByNameOrdered(name);
    }

    @GetMapping("/users/name/{name}/asc")
    public List<User> getUsersByNameOrderedAsc(@PathVariable String name) {
        return userService.getUsersByNameOrderedAsc(name);
    }
}

Step 6: Compare the Records

Also, you may compare the records with the specified value using the \ and \= operators by utilizing the LessThan and LessThanEqual keywords.

Java
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;

public interface UserRepository extends JpaRepository<User, Integer> {

    List<User> findUsersByAgeBelow(Integer age);

    List<User> findUsersByAgeAtMost(Integer age);
    
}

Step 7: Limit the Number of Results

You can use Hibernate or any other JPA implementation to limit the number of returned records on the Query interface.

Java
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;

public interface CustomBookRepository extends JpaRepository<Book, Long> {
    
    List<Book> findTop5ByTitleOrderByTitleAsc(String title);
    
}

Explanation:

  • The JpaRepository interface from Spring Data JPA offers more query options for entities in addition to CRUD operations.
  • An extension of the JpaRepository is the CustomBookRepository interface. This enables it to inherit the usual CRUD operations as well as extra query capabilities for Book entities, where the type of the entity is Long and the entity type is Book.

Step 8: Sorting and Paging

Lastly, you can add paging and sorting parameters to your methods.

Java
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

public interface UserRepository extends JpaRepository<User, Long> {
    Page<User> findByAgeGreaterThan(int age, Pageable pageable);
}

Explanation:

  • public interface UserRepository extends JpaRepository<User, Long>, describes the JpaRepository-extending UserRepository interface. JpaRepository is a Spring Data interface that offers additional features for entities in addition to the basic CRUD (Create, Read, Update, Delete) activities. In this case, the entity type is User, and the ID type of the entity is Long.
  • You supply a Pageable object and an age value to the findByAgeGreaterThan function.
  • To filter the User entities based on their age, utilize the age option.
  • Page<User> findByAgeGreaterThan(int age, Pageable pageable), the repository interface defines this particular custom query method.

Conclusion

This article covers Derived Query Methods in Spring Data JPA Repositories with code and explanation, Spring Data JPA Repository is a Java Persistence API (Ja PA)-a specific extension of Repository. It includes the full APIs for CrudRepository and PagingAndSortingRepository. So it has APIs for basic CRUD activities, as well as pagination and sorting.


Next Article

Similar Reads