Skip to content

Repositories

BrunoRosendo edited this page Aug 13, 2023 · 7 revisions

Repositories are the next layer above the Models. They are an abstraction whose goal is to significantly reduce the amount of boilerplate code required to implement data access to our entities. This is one of the features that Spring automates the best, as you'll see in the following chapters.

[Spring Docs] about repositories is very good, so this section of the Wiki will be shorter and mostly limited to the features used in the project.

Contents

Creating a Repository

To establish a repository that is readily usable, you can effortlessly define an interface that extends the Repository interface and is marked with the @Repository annotation. To accurately formulate this interface, you will need to specify the two generics: one for the entity and the other for the ID type (usually Long). Spring will then take care of all the necessary setup for the query system (yes, this feature is a bit magical).

Nevertheless, there are different types of repositories and it's crucial to comprehend the main distinctions prior to their utilization:

  • Repository: Principally operates as a marker interface, aiding in the identification of interfaces that extend it. It is rarely used unless customizations are being implemented, as it lacks useful methods.
  • CrudRepository: Offers CRUD operations for the specified entity, including reading, creation, updating, and deletion. This interface is the most commonly used.
  • PagingAndSortingRepository: Extends Repository and provides extra methods to handle pagination and sorting mechanisms. It's often combined with CrudRepository to include CRUD methods.
  • ListCrudRepository / ListPagingAndSortingRepository: Equal to their non-list counterparts, but return a List instead of an Iterable whenever applicable.
  • CoroutineCrudRepository / CoroutineSortingRepository: Equal to their non-coroutine counterparts, but using Kotlin Coroutines.
  • JpaRepository: An extension of ListCrudRepository, JpaRepository is a specialized JPA implementation of repositories. It essentially inherits the features of ListCrudRepository while incorporating additional functionalities, like methods for flushing pending alterations to the database. It is advisable to utilize the more generalized interfaces unless specific requirements necessitate the use of JpaRepository.

If you ever need to create your own abstraction for repositories, you can create an interface with the @NoRepositoryBean to prevent Spring from initializing it.

To actually create the repository, you need just two lines of code:

@Repository
interface RoleRepository : CrudRepository<Role, Long>

Sources: Spring Docs and StackOverflow

Defining Queries

The default repositories come with handy methods, but they might not cover all the queries we need. In Spring, we can easily define most queries by just creating a method in an interface following a specific pattern. Spring takes care of parsing the method name and generating the correct query! You can find the potential queries and their formats in the documentation, but here are a few examples.

Additionally, you can craft custom queries in a SQL-like language called JPQL using the @Query annotation. There's even an optional parameter nativeQuery to construct raw SQL queries.

@Repository
interface GenerationRepository : CrudRepository<Generation, Long> {
    // Returns null if not found
    fun findBySchoolYear(schoolYear: String): Generation?

    // Orders generations and retrieves the first one
    fun findFirstByOrderBySchoolYearDesc(): Generation?

    @Query("SELECT schoolYear FROM Generation ORDER BY schoolYear DESC")
    fun findAllSchoolYearOrdered(): List<String>
}
@Repository
interface AccountRepository : PagingAndSortingRepository<Account, Long>, CrudRepository<Account, Long> {
    // Search for both name and email
    fun findByNameAndEmail(name: String, email: String): List<Account>

    // Search for either name or email
    fun findDistinctByNameOrEmail(name: String, email: String): List<Account>

    // Case insensitive query
    fun findByNameIgnoreCase(name: String): List<Account>

    // Using pagination
    fun findByName(name: String, pageable: Pageable): Page<Account>
}

Source: Spring Docs