You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

@ManyToOne关联审计异常:entity_b_audit中entity_a_id始终为空求助

问题分析

你当前的核心问题是:entity_b_audit表中entity_a_id字段始终为空,原因在于EntityA的自增ID是插入数据库后才生成的,而Envers审计时无法捕获这个延迟生成的关联ID;同时为了避免Envers生成不需要的中间审计表,你在EntityA的OneToMany关联上添加了@NotAudited,进一步导致关联字段的审计逻辑缺失。

解决方案

方案一:显式维护EntityB的关联ID字段(无需改动ID结构)

修改EntityB,新增一个可插入的entityAId字段,手动同步关联的EntityAID,确保Envers能审计到该字段:

@Entity
@Audited
@Table(name = "entity_b")
public class EntityB {

    @Id
    @Column(name = "entity_b_uuid", columnDefinition = "char", updatable = false)
    @Type(type = "uuid-char")
    private UUID uuid = UUID.randomUUID();

    // 新增显式存储的entity_a_id,允许插入
    @Column(name = "entity_a_id", nullable = false)
    private Integer entityAId;

    @ManyToOne(optional = false, fetch = FetchType.LAZY)
    @JoinColumn(name = "entity_a_id", insertable = false, updatable = false)
    private EntityA entityA;

    // 关联EntityA时同步设置ID
    public void setEntityA(EntityA entityA) {
        this.entityA = entityA;
        this.entityAId = entityA.getId();
    }
}

同时在EntityA中添加关联方法,确保同步设置:

public void addEntityB(EntityB entityB) {
    entityBs.add(entityB);
    entityB.setEntityA(this);
}

这样保存EntityB时,显式的entityAId会被Envers审计,存入entity_b_audit表。

方案二:改用UUID作为EntityA的主键(推荐,符合代码设计意图)

既然EntityA的自增ID已标记为@Deprecated,直接将UUID设为主键,避免ID延迟生成的问题:

修改EntityA

@Entity
@Table(name = "entity_a")
@Audited
public class EntityA {

    @Id // 将UUID设为主键
    @Column(name = "entity_a_uuid", columnDefinition = "char", updatable = false)
    @Type(type = "uuid-char")
    private UUID uuid = UUID.randomUUID();

    /**
     * @deprecated in favor of uuid
     */
    @Deprecated
    @GeneratedValue
    @Column(name = "entity_a_id", updatable = false)
    private Integer id;

    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
    @JoinColumn(name = "entity_a_uuid", nullable = false) // 关联改为UUID字段
    @BatchSize(size = 100)
    @NotAudited
    private List<EntityB> entityBs = new ArrayList<>();
}

修改EntityB

@Entity
@Audited
@Table(name = "entity_b")
public class EntityB {

    @Id
    @Column(name = "entity_b_uuid", columnDefinition = "char", updatable = false)
    @Type(type = "uuid-char")
    private UUID uuid = UUID.randomUUID();

    @Column(name = "entity_a_uuid", nullable = false)
    private UUID entityAUuid;

    @ManyToOne(optional = false, fetch = FetchType.LAZY)
    @JoinColumn(name = "entity_a_uuid", insertable = false, updatable = false)
    private EntityA entityA;

    public void setEntityA(EntityA entityA) {
        this.entityA = entityA;
        this.entityAUuid = entityA.getUuid();
    }
}

此方案从根源解决了ID延迟生成的问题,同时符合代码中弃用自增ID的设计,审计表中会正确存储entity_a_uuid字段。

方案三:自定义Envers审计监听器(无实体/表结构改动)

如果无法修改实体或表结构,可自定义审计监听器,手动填充关联字段:

public class CustomEntityBAuditListener extends AuditEventListener {
    @Override
    public void onPostInsert(PostInsertEvent event) {
        super.onPostInsert(event);
        if (event.getEntity() instanceof EntityB) {
            EntityB entityB = (EntityB) event.getEntity();
            EntityA entityA = entityB.getEntityA();
            if (entityA.getId() != null) {
                AuditReader auditReader = AuditReaderFactory.get(event.getSession());
                List<Number> revisions = auditReader.getRevisions(EntityB.class, entityB.getUuid());
                if (!revisions.isEmpty()) {
                    Number latestRevision = revisions.get(revisions.size() - 1);
                    EntityB auditedEntityB = auditReader.find(EntityB.class, entityB.getUuid(), latestRevision);
                    auditedEntityB.setEntityAId(entityA.getId());
                    event.getSession().saveOrUpdate(auditedEntityB);
                }
            }
        }
    }
}

在Hibernate配置中注册监听器:

<property name="hibernate.ejb.event.post-insert" value="com.yourpackage.CustomEntityBAuditListener"/>

此方案实现复杂,需处理事务同步,仅推荐在无法修改实体时使用。

内容的提问来源于stack exchange,提问作者braab

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 01:20:46