【问题标题】:JPA Soft Delete Repository + AuditingJPA 软删除存储库 + 审计
【发布时间】:2020-02-05 22:54:15
【问题描述】:

我需要实现 JPA 软删除存储库并同时支持多个列的 JPA 审计。 目前,我已经通过 EL 和 @Query+@Modifying 注解实现了 Soft Delete 存储库:

    @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();

但是对于这样的实现,审计列不会更新,因为如果我理解正确,@Query 注释不会触发任何生命周期回调方法。

实体级别的@Where 注释不是一个选项,因为需要有可能查询软删除的实体。

您能否提供任何其他可能的解决方案?

【问题讨论】:

  • 您从哪里读到/得知@Query 不会触发 LC 回调?
  • 好吧,我自己试过了,在上述删除方法的情况下,JPA AuditingEntityListener 和我的自定义审计侦听器都没有被调用(@PreUpdate 方法)。我还在 StackOverflow 上发现了这个问题:stackoverflow.com/questions/56823730/…

标签: java spring jpa spring-data-jpa


【解决方案1】:

如果您使用的是 Hibernate,那么您可以自定义在删除时执行的 SQL,以便将活动标志设置为 false,而不是发出删除语句。在这种情况下,您将调用EntityManager#remove(通过 Spring Data 的存储库抽象),然后生命周期侦听器将按预期执行。

@SQLDelete(sql = "UPDATE someEntity SET active= 0 WHERE id = ?", 
                    check ResultCheckStyle.COUNT)
@Entity
public class SomeEntity{

    //if SomeChildEntity has similar @SqlDelete clause then would be 'deleted' also
    @OneToMany(cascade = CascadeType.REMOVE)
    private Set<SomeChildEntity> children;
}

这有一个额外的好处,即级联删除也应该按预期执行,而在使用批量删除时它们不会执行。

【讨论】:

  • 感谢您的回答。我见过这个注解,但我没有考虑将它作为一个选项,因为不可能在基础MappedSuperClass 实体上使用这个注解,因为这个注解需要表名。
  • 我想我会尝试将删除方法设为默认方法,我将在其中更新活动标志列并调用通用保存存储库方法。
【解决方案2】:

更新: 我决定使用覆盖的默认删除存储库方法将活动标志更新为“false”并通过常见的save() 方法保存实体。

    @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);
        }
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-05-18
    • 2020-01-21
    • 2021-07-25
    • 1970-01-01
    • 2014-01-10
    • 2014-10-29
    • 1970-01-01
    • 2021-07-06
    相关资源
    最近更新 更多