0

给定一个由 Envers 审计的实体,其中包含一个集合。

实体 A

  @Audited
    public class A{
     @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    ....
    @OneToMany
    @JoinColumn(name = "a_id")
    @AuditJoinTable(name = "A_B_AUDIT"
            ,inverseJoinColumns = @JoinColumn(name = "a"))
    private List<B> bs;
    ....
}

实体 B

@Audited
public class B{
 @Id
 private int id;
 ....
 @Column(name = "a_id")
 private int aId;

 @ManyToOne
 @JoinColumn(name = "a_id", insertable = false, updatable = false)
 private A a;
}

根据他们的文档 ,Envers 将添加和删除的审计信息存储到这些 AuditJoinTables (A_B_AUDIT)。但不幸的是,这不起作用,并且表中的行丢失了。

当我运行我的项目时,会创建以下表格:

A_AUDIT

B_AUDIT

A_B_AUDIT

我有单独的控制器来持久化 A 对象和 B 对象。当我尝试使用 aId 和 A 保存 B 时,audit_table ( A_B_AUDIT ) 不会更新,但更新版本的B_AUDIT会更新。

有人可以让我知道我在这里缺少什么。

谢谢 !!

Hibernate Enver 版本:5.1.4.Final

4

1 回答 1

1

正如评论中所说,您的问题是您在单独的事务中执行这两个实体的持久性,但您没有进行正确的关联,因此您污染了 Hibernate 的一级缓存的状态。无意中,您还导致 Envers 无法正确审核您的实体,因为您没有为其提供所有正确的状态。

为了让这个用例与 Envers 一起使用,您需要修改处理 Entity 持久性的方式B,因为它似乎是唯一知道与 Entity 关系的东西A

在 Entity 的持久化过程中B,您可能应该这样做:

if ( b.getAId() != null ) {
  A a = entityManager.find( A.class, b.getAId() );
  a.getBs().add( b );
  a = entityManager.merge( a );

  b.setA( a );
  entityManager.persist( b );
}

这意味着在 Entity 的持久化期间B,您应该像预期的那样在审计连接表中添加一个审计行,并且 Hibernate 一级缓存中的状态将包含两个实体之间的所有正确引用。

如果我们暂时搁置 Envers 并专注于正常的 JPA 提供程序使用,您应该能够在坚持 B 之后执行此操作,并且它会起作用:

final A theA = b.getA();
assertNotNull( theA );
assertTrue( !theA.getBs().isEmpty() );
assertTrue( theA.getBs().contains( b ) );

显然,如果您不设置关联,则这些断言(应该全部通过)不会。他们唯一会通过的时间是您重新查询 entity 时B,但这不是必需的。

希望你明白。

于 2017-12-13T13:47:24.443 回答