2016-12-14 34 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