Spring Data JPA Delete and Relationships

1. Overview

In this tutorial, we’ll have a look at how deleting is done in Spring Data JPA.

2. Sample Entity

As we know from the Spring Data JPA reference documentation, repository interfaces provide us some basic support for entities.

If we have an entity, like a Book:

@Entity
public class Book {

    @Id
    @GeneratedValue
    private Long id;
    private String title;

    // standard constructors

    // standard getters and setters
}

Then, we can extend Spring Data JPA’s CrudRepository to give us access to CRUD operations on Book:

@Repository
public interface BookRepository extends CrudRepository<Book, Long> {}

3. Delete from Repository

Among others, CrudRepository contains two methods: deleteById and deleteAll.

Let’s test these methods directly from our BookRepository:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = {Application.class})
public class DeleteFromRepositoryUnitTest {

    @Autowired
    private BookRepository repository;

    Book book1;
    Book book2;
    List<Book> books;

    // data initialization

    @Test
    public void whenDeleteByIdFromRepository_thenDeletingShouldBeSuccessful() {
        repository.deleteById(book1.getId());
        assertThat(repository.count()).isEqualTo(1);
    }

    @Test
    public void whenDeleteAllFromRepository_thenRepositoryShouldBeEmpty() {
        repository.deleteAll();
        assertThat(repository.count()).isEqualTo(0);
    }
}

And even though we are using CrudRepository, note that these same methods exist for other Spring Data JPA interfaces like JpaRepository or PagingAndSortingRepository.

4. Derived Delete Query

We can also derive query methods for deleting entities. There is a set of rules for writing them, but let’s just focus on the simplest example.

A derived delete query must start with deleteBy, followed by the name of the selection criteria. These criteria must be provided in the method call.

Let’s say that we want to delete Books by title. Using the naming convention, we’d start with deleteBy and list title as our criteria:

@Repository
public interface BookRepository extends CrudRepository<Book, Long> {
    long deleteByTitle(String title);
}

The return value, of type long, indicates how many records the method deleted.

Let’s write a test and make sure that is correct:

@Test
@Transactional
public void whenDeleteFromDerivedQuery_thenDeletingShouldBeSuccessful() {
    long deletedRecords = repository.deleteByTitle("The Hobbit");
    assertThat(deletedRecords).isEqualTo(1);
}

Persisting and deleting objects in JPA requires a transaction, that’s why we should use a @Transactional annotation when using these derived delete queries, to make sure a transaction is running. This is explained in detail in the ORM with Spring documentation.

5. Custom Delete Query

The method names for derived queries can get quite long, and they are limited to just a single table.

When we need something more complex, we can write a custom query using @Query and @Modifying together.

Let’s check the equivalent code for our derived method from earlier:

@Modifying
@Query("delete from Book b where b.title=:title")
void deleteBooks(@Param("title") String title);

Again, we can verify it works with a simple test:

@Test
@Transactional
public void whenDeleteFromCustomQuery_thenDeletingShouldBeSuccessful() {
    repository.deleteBooks("The Hobbit");
    assertThat(repository.count()).isEqualTo(1);
}

Both solutions presented above are similar and achieve the same result. However, they take a slightly different approach.

The @Query method creates a single JPQL query against the database. By comparison, the deleteBy methods execute a read query, then delete each of the items one by one.

6. Delete in Relationships

Let’s see now what happens when we have relationships with other entities.

Assume we have a Category entity, that has a OneToMany association with the Book entity:

@Entity
public class Category {

    @Id
    @GeneratedValue
    private Long id;
    private String name;

    @OneToMany(mappedBy = "category", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Book> books;

    // standard constructors

    // standard getters and setters
}

The CategoryRepository can just be an empty interface that extends CrudRepository:

@Repository
public interface CategoryRepository extends CrudRepository<Category, Long> {}

We should also modify the Book entity to reflect this association:

@ManyToOne
private Category category;

Let’s now add two categories and associate them with the books we currently have. Now, if we try to delete the categories, the books will also be deleted:

@Test
public void whenDeletingCategories_thenBooksShouldAlsoBeDeleted() {
    categoryRepository.deleteAll();
    assertThat(bookRepository.count()).isEqualTo(0);
    assertThat(categoryRepository.count()).isEqualTo(0);
}

This is not bi-directional, though. That means that if we delete the books, the categories are still there:

@Test
public void whenDeletingBooks_thenCategoriesShouldAlsoBeDeleted() {
    bookRepository.deleteAll();
    assertThat(bookRepository.count()).isEqualTo(0);
    assertThat(categoryRepository.count()).isEqualTo(2);
}

We can change this behavior by changing the properties of the relationship, such as the CascadeType.

7. Conclusion

In this article, we looked at different ways to delete entities in Spring Data JPA. We looked at the provided delete methods from CrudRepository, as well as our derived queries or custom ones using @Query annotation.

We also had a look at how deleting is done in relationships. As always, all of the code snippets mentioned in this article can be found on our GitHub repository.

Related posts:

How to Add a Single Element to a Stream
Java Program to Implement Euclid GCD Algorithm
Create Java Applet to Simulate Any Sorting Technique
Write/Read cookies using HTTP and Read a file from the internet
The Registration Process With Spring Security
Template Engines for Spring
Java Program to Create a Random Graph Using Random Edge Generation
Spring Autowiring of Generic Types
Hashtable trong java
A Guide to Spring Cloud Netflix – Hystrix
Java Program to Check Whether Topological Sorting can be Performed in a Graph
Các kiểu dữ liệu trong java
Java Program to Check Whether a Directed Graph Contains a Eulerian Cycle
Get and Post Lists of Objects with RestTemplate
Java Program to Apply DFS to Perform the Topological Sorting of a Directed Acyclic Graph
Checked and Unchecked Exceptions in Java
Java Program to Implement the Hill Cypher
Hướng dẫn Java Design Pattern – Strategy
Spring Boot Actuator
Introduction to Spring Data REST
Apache Commons Collections BidiMap
Iterating over Enum Values in Java
Java Program to Implement First Fit Decreasing for 1-D Objects and M Bins
Hướng dẫn Java Design Pattern – Facade
Java Program to Perform Encoding of a Message Using Matrix Multiplication
Hướng dẫn Java Design Pattern – Memento
Java Program to Implement Naor-Reingold Pseudo Random Function
Java Program to Implement Network Flow Problem
Java Program to Implement K Way Merge Algorithm
Spring Data Reactive Repositories with MongoDB
Java InputStream to String
Java Program to Check whether Graph is a Bipartite using 2 Color Algorithm