我正在使用 hibernate.envers 设置:
properties.put("org.hibernate.envers.audit_table_suffix", "_HISTORY");
properties.put("org.hibernate.envers.store_data_at_delete", "true");
主表如下:
@Entity
@Table(name = "person")
@SQLDelete(sql = "UPDATE person SET deleted = NOW() WHERE id = ?", check = ResultCheckStyle.COUNT)
@Where(clause = "deleted is NULL")
@Audited
public class Person {
@Id
private UUID id;
private OffsetDateTime deleted;
//omit other fields
}
当删除事件发生时,Person_HISTORY表将存储除deleted
字段之外的Person的所有字段。 (Person_HISTORY
表中的deleted
字段为空)
知道如何在删除事件发生时将deleted
字段存储到Person_HISTORY中吗?
最佳答案
简单来说,对deleted
的修改不包含在PostDeleteEvent
中。
Hibernate 在实体删除工作流程开始时构建一次包含在 PostDeleteEvent
中的状态。对于传统用途,这是有意义的,因为正在执行的语句是DELETE
,因此该行不会被修改。
这里的难题是 @SQLDelete
仅用自定义版本替换实体持久化器使用的生成的 DELETE
语句。一般来说,您提供的 SQL 可以是任何内容,只要它是语法上有效的 DML 即可。
Hibernate 不知道的是,本例中的替换 SQL 是 UPDATE
。因此,在持久化程序执行删除 SQL 语句之后,不会发生持久化程序快照状态的重新同步,并且事件的状态不会发生更改,并且当 post-delete 回调触发时,它们仍然会被提供实体删除工作流程开始时的状态。
话虽如此,Envers 确实在审核表中记录了 REVTYPE=2
(又名 DEL
)。因此,如果您需要删除的时间戳,您仍然可以从 Envers REVINFO
表中获取它。
更新
这里的另一个想法是使用两列而不是单列。不要使用时间戳作为软删除指示器,而是使用位标志
@Entity
@Audited
@SQLDelete("UPDATE person SET deleted = true WHERE id = ?")
@Where(clause = "deleted is NULL or deleted != true")
public class Person {
@NotAudited
private boolean deleted;
private OffsetDateTime deleteTime;
@PreRemove
public void onPreRemove() {
this.deleteTime = ...;
}
}
这里我使用 @PreRemove
来设置删除时间值,然后将该值在 PostDeleteEvent
中传递给 Envers,并让 Hibernate 管理位字段。由于事件状态中从未提供 deleted
字段,因此我将其标记为 @NotAudited
以将其从审核架构中排除。
关于java - Hibernate Enver 不审核软删除中使用的字段?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50245463/