Hibernate @SoftDelete Step-by-Step Guide

@SoftDelete annotation, introduced in Hibernate version 6.4, provides first-class support for soft deletes, allowing to logically mark rows rows as deleted without actually removing them from the Database. In this tutorial we will see a proof of concept example of @SoftDelete and its common configuration attributes.

What is a Soft Delete?

A Soft Delete marks a Database record as no longer active or valid without physically deleting it. In a nutshell, it adds metadata in your Table indicating which data should be considered deleted.

Soft deletes can be beneficial in several scenarios, such as:

  • You want to be able to recover your data before you delete it permanently. This is especially useful in the testing phase.
  • You want to audit Statements before you actually delete them
  • To keep referential integrity between Tables

Let’s see in practice how to create a simple Maven project which uses Hibernate 6.4 and SoftDelete. To learn how to set up an Hibernate Project with Maven we recommend the following article: Hibernate 6 with Maven made simple

Implementing SoftDelete in Hibernate

Hibernate includes support for SoftDeletes since version 6.4, therefore you need to use this version or a newer one:

<dependency>
      <groupId>org.hibernate.orm</groupId>
      <artifactId>hibernate-core</artifactId>
      <version>6.4.0.Final</version>
</dependency>

Then, to use SoftDelete in Hibernate you can place the annotation @SoftDelete either on a Column or on an Entity as in the following example:

@Entity
@SoftDelete(columnName = "removed")
public class Customer implements Serializable {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Integer id;

  @Column
  private String email;

  @Column
  private String firstName;

  @Column
  private String lastName;

  // Omitted for brevity

}

Please notice the optional attribute (columnName = "removed") which we can use to indicate the column name to mark the Row as Deleted. Later on we will also discuss other available options

Next, we will add a simple Class to insert and delete a row in the Customer Table that backs the above Entity.

public class SoftDeleteExample {

  public static void main(String[] args) {
 

    EntityManagerFactory emf = Persistence.createEntityManagerFactory("persistence01");

    Customer c = new Customer();
    c.setFirstName("John");
    c.setLastName("Doe");
    c.setEmail("[email protected]");

    EntityManager entityManager = emf.createEntityManager();

    entityManager.getTransaction().begin();
    entityManager.persist(c);
    entityManager.getTransaction().commit();

    entityManager.getTransaction().begin();
    entityManager.remove(c);
    entityManager.getTransaction().commit();

    List<Customer> customers = entityManager.createQuery("SELECT c FROM Customer c", Customer.class)
        .getResultList();

    for (Customer customer : customers) {
      System.out.println(customers);
    }

    List<Customer> nativeCustomers = entityManager.createNativeQuery("SELECT * FROM Customer c", Customer.class)
        .getResultList();

    System.out.println("Native query");
    for (Customer customer : nativeCustomers) {
      System.out.println(customer);
    }
    entityManager.close();
    emf.close();

  }
}

The purpose of this Class is pretty simple. We will first add a Customer Entity. After that, we will delete it. Since the Entity uses @SoftDelete for its rows, we should see a different outcome when using Hibernate Query and plain Native Query.

Running our example

Let’s run our example:

mvn exec:java

When we insert our Customer Entity, the following Data will be available in the Database:

hibernate 6.4 @softdelete

As you can see, the Table Customer includes an extra column “removed” according to our annoation @SoftDelete(columnName = “removed”).

Then, if we remove the Entity, the Data will still be available in the DB, just the field removed is not set to “t”:

how to use hibernate 6.4 softdelete

Changing the SoftDelete Strategy

By default, when you use the @SoftDelete annotation on your code, it will use the DELETE Strategy. It means that behind the hoods Hibernate will set the attribute (removed) to true when you perform a soft delete:

Hibernate: update Customer set removed=true where id=? and removed=true

Another possible approach is to use the ACTIVE strategy:

@SoftDelete(strategy= SoftDeleteType.ACTIVE)

This strategy works in the opposite way. When you soft delete an Entity, it will mark is as not active:

Hibernate: update Customer set active=false where id=? and active=true

The difference lies in the interpretation of the indicator values in the database. The ACTIVE strategy interprets true as an active row and false as deleted, while the DELETED strategy interprets true as deleted and false as an active row.

Finally, it is also possible to use a Custom Converter as Strategy to map a SoftDelete with a character. For example, you could use a YesNoConverter :

SoftDelete(converter = YesNoConverter.class)

Conclusion

By leveraging soft deletes in Hibernate, you can maintain data integrity, comply with regulations, improve data recovery processes, and implement various application-specific functionalities without permanently removing records from your database.

Source code for this article: https://github.com/fmarchioni/mastertheboss/tree/master/hibernate/soft-delete