给定由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;
}
根据他们的documentation Envers存储审计信息,以便添加和删除这些AuditJoinTables(A_B_AUDIT)。但不幸的是,这不起作用,表中的行也丢失了。
当我运行我的项目后,表格被创建:
A_AUDIT
B_AUDIT
A_B_AUDIT
我已经将控制器分开来持久存在一个对象和一个B对象。当我尝试使用aId和A保存B时,audit_table( A_B_AUDIT )不会更新,但更新版本的 B_AUDIT 会更新。
有人可以让我知道我在这里缺少什么。
谢谢!
Hibernate Enver版本:5.1.4.Final
答案 0 :(得分:1)
如评论中所述,您的问题是您在单独的事务中执行这两个实体的持久性,但是您没有进行正确的关联,因此您正在污染Hibernate的第一级缓存的状态。无意中,您还导致Envers无法正确审核您的实体,因为您没有给它所有正确的状态。
为了让这个用例与Envers一起使用,你需要修改你处理实体B
持久性的方式,因为它是唯一似乎知道的关于与实体A
的关系。
在实体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 );
}
这意味着在实体B
的持久性期间,您应该像审计的那样在审计连接表中添加一个审计行,并且Hibernate一级缓存中的状态将包含两个实体之间的所有正确引用
如果我们暂时搁置Envers并专注于正常的JPA提供程序使用,你应该能够在持久化B之后执行此操作并且它可以工作:
final A theA = b.getA();
assertNotNull( theA );
assertTrue( !theA.getBs().isEmpty() );
assertTrue( theA.getBs().contains( b ) );
显然,如果你没有设置关联,这些断言(应该全部通过)都不会。他们通过的唯一时间是你重新查询实体B
,但这不是必要的。
希望你明白。