Java 休眠-至少有一个孩子
这个问题有点问我想要实现什么,但实际上没有答案: 我有两个对象(A和B)。A是父母。B是孩子。这是一个一对多的关系,但是,我需要每个a始终至少有一个B。B中的所有字段都有默认值,因此如果创建a时没有B,则可以添加默认B以确保始终有一个B。如果添加一个或多个B对象a,则无需创建默认B 这是一个:Java 休眠-至少有一个孩子,java,hibernate,Java,Hibernate,这个问题有点问我想要实现什么,但实际上没有答案: 我有两个对象(A和B)。A是父母。B是孩子。这是一个一对多的关系,但是,我需要每个a始终至少有一个B。B中的所有字段都有默认值,因此如果创建a时没有B,则可以添加默认B以确保始终有一个B。如果添加一个或多个B对象a,则无需创建默认B 这是一个: [Fields] @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) @JoinColumn(name = "key", nullab
[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";
}
...
}
我想我可以在A中使用相同的@PrePersist注释,检查是否有任何B对象,如果没有,则创建默认B:
@PrePersist
protected void onCreate() {
// Deafult values configured here
...
if (b.size() == 0) {
b.add(new B());
}
}
那不行。如果我创建了一个没有B对象的A,那么在日志中我只得到:
删除处理中瞬态实体的处理
而A是在没有B的情况下创建的。如果我尝试使用至少一个B创建A,则会出现以下错误:
原因:org.hibernate.transientObject异常:对象引用
未保存的临时实例-在之前保存临时实例
冲洗
你知道我该怎么做吗 在不了解更多代码的情况下(不管怎么说,这可能有点太多),我不得不做一些假设,但我要说的是,当调用
onCreate()
时,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
将是所有者,但这可能会导致问题,因为您必须在flush期间更改A
实例以保持关系。如果B
是拥有方(它有一个对a
的反向引用,并且在a
中,您的@OneToMany
中有一个映射,它应该可以工作
编辑:
实际上,可能还有第三种选择:当您创建一个新元素时,添加一个默认元素,当添加真实元素时,删除它。这样,您就不必处理Hibernate会话或事务作用域。顺便说一句,我想推荐您提出这个问题。很少有新的投稿人在他们的问题上投入这么多精力。@Thomas,谢谢你的好话。这可能是我的第一个问题,但我已经在这里潜伏了很多年:)我看到了好的问题和坏的问题,这有助于了解如何最好地组织它。第三个选项是我首先想到的,因为这不应该给hibernate部分增加任何复杂性(有时可能会很棘手)@XtremeBaumer哦,是的,它可以:)谢谢你解释我为什么看到这些消息/错误。有道理。我试图在hibernate级别拦截缺少子对象的情况,因为这似乎是有意义的,特别是因为我已经在@PrePersist中设置了默认值。你的第三个选择无疑是一条路要走,因为似乎没有一个简单的hibernate方法来解决这个问题。我已经实现了您的建议,在rest控制器中创建默认子对象效果很好。
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 ) );
}