2016-12-14 53 views
0

我们有以下实体层次和EntityListenerEnvers - 在EntityListener @PreUpdate新元素添加到收藏一对多

@Entity 
@EntityListeners(value = DummyListener.class) 
@Audited 
public class A { 
@OneToMany(cascade = CascadeType.ALL, mappedBy = "a", fetch = FetchType.LAZY, orphanRemoval = true) 
    @Fetch(FetchMode.SELECT) 
    private Set<B> bs = new LinkedHashSet<B>(0); 
} 

@Entity 
@Audited 
public class B { 
    @ManyToOne(fetch = FetchType.EAGER, cascade = { CascadeType.MERGE, CascadeType.PERSIST }) 
    @JoinColumn(name = "a_id", nullable = false) 
    private A a; 
} 

public class DummyListener { 
    @PreUpdate 
    public void beforeUpdate(A entity) { 
    entity.set...(...); 

    ... 

    B old = entity.getBs().iterator().next(); 
    old.set...(...); 

    ... 

    B b = new B(); 
    b.setA(entity); 

    entity.getBs().add(b); 
    ... 
    } 

}

在实体监听器,我们希望新型B实体添加到实体集合。但是在保存A之后,envers没有在B审计表中为新的B实例创建审计记录。 除了新的B实例外,其他所有更改都具有审计记录。

我们错了什么?以这种方式创建B的新实例是可能的吗?

回答

1

每JPA规格2.1:

一般来说,便携式应用程序不应该调用EntityManager的或查询业务的生命周期方法,访问其他实体的情况下,或修改同一持久化上下文中的关系。

的这里的一点是,通过添加新B和它有关A意味着你正在修改的实体之间的关系,尽管是一个新的实体B

因此,采取下面的代码:

@PreUpdate 
public void onPreUpdate(Object object) { 
    if (object instanceof A) { 
    final A a = (A) object; 
    final B b = new B(); 
    b.setA(a); 
    a.getBs().add(b); 
    } 
} 

如果这个测试只用Hibernate和没有审计,你会注意到的B新实例的生命周期回调中创建其时,甚至没有坚持​​。因此,如果Hibernate不允许使用这种用例,Envers甚至无法检测到状态变化并执行必要的收集工作单元。

+0

感谢您的回答!我也从JPA文档中找到了答案,所以我们应该找到另一种方法来创建类似方法的触发器,或者将逻辑移入另一个服务器端实现。 – SeniorRoland