这个问题问我要达到的目标,但实际上并没有答案:Hibernate validateManyToOne
has at least one
我有两个对象(A和B)。 A是父母。 B是孩子。这是一对多的关系,但是,我需要每个A至少有一个B。B中所有字段都有默认值,因此,如果创建的A没有B,则可以将默认B添加到确保始终有一个B。如果添加了一个或多个B对象,则无需创建默认B。
这是A:
[Fields]
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "key", nullable = false)
@Fetch(value = FetchMode.SUBSELECT)
private List<B> b = new ArrayList<>();
...
@PrePersist
protected void onCreate() {
// Default values configured here, for example
if (fieldA1 == null) {
fieldA1 = "A DEFAULT";
}
...
}
这是B:
[Fields]
@PrePersist
protected void onCreate() {
// Default values configured here, for example
if (fieldB1 == null) {
fieldB1 = "B DEFAULT";
}
...
}
我以为我可以在A中使用相同的@PrePersist批注,检查是否有B对象,如果没有,则创建默认的B:
@PrePersist
protected void onCreate() {
// Deafult values configured here
...
if (b.size() == 0) {
b.add(new B());
}
}
那是行不通的。如果我创建一个没有B对象的A,那么在日志中我只会得到:
在删除处理中处理瞬态实体
并且创建了一个不带B的A。如果我尝试创建一个至少包含一个B的A,则会出现以下错误:
由于:org.hibernate.TransientObjectException:对象引用 未保存的瞬态实例-在保存瞬态实例之前 冲洗
有什么想法可以使我工作吗?
答案 0 :(得分:0)
在不了解更多代码的情况下(无论如何对SO来说可能有点过多),我将不得不做一些假设,但是我想说的是,onCreate()
被调用时,Hibernate会话已经处于“刷新”状态,因此将不接受任何新实体。
目前,我可以想到在某些情况下也会使用的2个选项:
在当前事务成功完成后,引发CDI事件并让事件处理程序(异步)触发新事务中默认元素的创建。
在Hibernate中创建一个子会话,该子会话从当前会话派生,并使用相同的事务。然后使用此子会话创建默认元素。
这是我们在休眠PostInsertEventListener
中进行的操作:
if( postInsertEvent.getEntity() instanceof ClassThatNeedsToBeHandled ) {
ClassThatNeedsToBeHandled insertedEntity = (ClassThatNeedsToBeHandled )postInsertEvent.getEntity();
Session subSession = postInsertEvent.getSession().sessionWithOptions()
.connection() //use the same connection as the parent session
.noInterceptor() //we don't need additional interceptors
.flushMode( FlushMode.AUTO ) //flush on close
.autoClose( true) //close after the transaction is completed
.autoJoinTransactions( true ) //use the same transaction as the parent session
.openSession();
subSession.saveOrUpdate( new SomeRelatedEntity( insertedEntity ) );
}
要记住的一件事是我们的SomeRelatedEntity
是关系的所有者。您的代码表明A
是所有者,但可能会引起问题,因为在刷新期间必须更改A
实例才能保持关系。如果B
是拥有方(它有对A
的后向引用,并且在A
中,您的mappedBy
中有@OneToMany
),那么它应该起作用。>
编辑:
实际上,可能有第三个选择:创建新的A时添加默认元素,而添加实元素时将其删除。这样,您就不必弄乱Hibernate会话或事务作用域了。