删除@OneToMany关联父实体时Hibernate Envers向子审计表插入空ID
解决Hibernate Envers删除Batch时插入空ID到审计表的问题
问题核心原因是BatchTechnicalRecord实体对中间表的双重映射:你既通过@OneToMany + @JoinTable让Hibernate自动管理batch_technical_record_attachment表,又手动创建了BatchTechnicalRecordAttachment实体映射同一张表。这种冲突导致Envers在处理级联删除的审计日志时,无法正确获取中间表记录的ID,触发空值约束错误。
解决方案步骤
1. 替换BatchTechnicalRecord的关联配置
删除BatchTechnicalRecord中自动管理中间表的@OneToMany + @JoinTable代码,改为关联手动定义的中间表实体:
@Audited @Entity @Table(name = "batch_technical_record") public class BatchTechnicalRecord extends BaseEntity implements Serializable { // 替换原attachments关联,改为关联中间表实体 @OneToMany(mappedBy = "batchTechnicalRecord", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY) private List<BatchTechnicalRecordAttachment> attachmentRelations; ... }
2. 修正BatchTechnicalRecordAttachment的关联配置
确认中间表实体的关联配置无误,同时修正原foreignKey名称的重复错误:
@Audited @Entity @Table(name = "batch_technical_record_attachment") public class BatchTechnicalRecordAttachment extends BaseEntity implements Serializable { @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL) @JoinColumn(name = "id_attachment", referencedColumnName = "id", nullable = false, foreignKey = @ForeignKey(name = "fk_batch_technical_record_attachment_attachment")) private Attachment attachment; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "id_batch_technical_record", referencedColumnName = "id", nullable = false, foreignKey = @ForeignKey(name = "fk_batch_technical_record_attachment_batch_technical_record")) private BatchTechnicalRecord batchTechnicalRecord; ... }
3. 调整业务代码的关联操作
如果之前直接操作BatchTechnicalRecord.attachments,现在需要改为通过中间实体关联Attachment:
// 示例:添加Attachment到BatchTechnicalRecord BatchTechnicalRecord record = ...; Attachment attachment = ...; BatchTechnicalRecordAttachment relation = new BatchTechnicalRecordAttachment(); relation.setBatchTechnicalRecord(record); relation.setAttachment(attachment); record.getAttachmentRelations().add(relation);
4. 验证审计表结构
确保batch_technical_record_attachment_aud表的id字段非空约束正常,且ID生成策略与主表(继承自BaseEntity)一致。
原理说明
同时使用自动生成的中间表关联和手动实体映射时,Hibernate Envers无法正确跟踪中间表的变更逻辑:两种关联方式的审计规则冲突,导致删除操作时Envers无法获取中间表实体的ID,最终触发空值插入错误。统一使用实体类管理中间表后,Envers能正常跟踪其生命周期,正确生成审计日志。
内容的提问来源于stack exchange,提问作者Pedro Vitor
相关产品推荐
相关产品推荐

