javaspringjpaspring-data-jpa

JPA Soft Delete Repository + Auditing


I need to implement JPA Soft Delete repository and support JPA auditing for several columns at the same time. For now, I've implemented Soft Delete repository via EL and @Query+@Modifying annotations:

    @Override
    @Modifying
    @Query("update #{#entityName} e set e.active = false where e.id = ?1")
    void deleteById(UUID id);

    @Override
    default void delete(T entity)
    {
        deleteById(entity.getId());
    }

    @Override
    @Modifying
    @Query("update #{#entityName} e set e.active = false where e.id in ?1")
    void deleteAll(Iterable<? extends T> iterable);

    @Override
    @Modifying
    @Query("update #{#entityName} e set e.active = false")
    void deleteAll();

But with such implementation audit columns are not updated because if I correctly understand, @Query annotation doesn't trigger any Lifecycle Callback methods.

@Where annotation on the Entity level is not an option because there is the need to have a possibility to query soft deleted entities.

Could you please help with any other possible solutions?


Solution

  • UPDATE: I've decided to go with the overridden default delete repository methods to update an active flag to 'false' and save an entity via common save() method.

        @Override
        default void deleteById(UUID id)
        {
            Assert.notNull(id, "The given id must not be null!");
    
            Optional<T> entity = this.findById(id);
            entity.ifPresent(this::delete);
        }
    
        @Override
        default void delete(T entity)
        {
            Assert.notNull(entity, "The entity must not be null!");
    
            entity.setActive(Boolean.FALSE);
            this.save(entity);
        }
    
        @Override
        default void deleteAll(Iterable<? extends T> entities)
        {
            Assert.notNull(entities, "The given Iterable of entities must not be null!");
    
            for (T entity : entities)
            {
                this.delete(entity);
            }
        }
    
        @Override
        default void deleteAll()
        {
            for (T element : this.findAll())
            {
                this.delete(element);
            }
        }