【发布时间】:2010-11-19 23:08:11
【问题描述】:
我在我的应用程序中使用 Spring 和 JPA,但最近我对使用 DomainObjects 中的集合有点困惑。
例如:
假设我们有两个表:Parent 和 Child。一个父级可以有多个子级 (@OneToMany),一个子级只能有一个父级 (@ManyToOne)。我使用 Spring 在我的 ServiceLayer(不是 Dao - 工作单元模式)中处理我的事务上下文,它由 aop:config 在 context-application.xml 中配置。子集合被标记为 LazyLoading 集合。到目前为止一切正常。
现在的问题如下:
我的服务中需要一个方法,它创建一个新的 Parent 并在同一个事务中调用另一个方法来对新创建的 Parent 进行一些计算。在这些计算中,我必须调用 parent.getChildren()。显然这应该返回一个空集,因为新的父级在创建时不能有任何子级,但由于某种原因,我返回“null”而不是一个空集,这会导致 NullpointerException
为了创建父级,我尝试了以下 EntityManager 方法:
- 使用 entityManager.persist( parent ) - 没有成功,创建后集合为空。
- 使用 entityManager.merge( parent ) 并返回 parent 的新托管实例 - 结果相同。
两者都导致了一个空集。但我很确定,这些调用在同一个事务中,因为在事务之外我会收到一个 LazyLoadingException(而不是 NullPointer),此时(afaik)是正确的。另一方面,将已经存在的父级与 entityManager.findById() 一起使用会产生一个现有的集合(这意味着它可以像预期的那样工作)。为了解决这个问题,我尝试了几种方法,直到找到一个可行的方法:
entityManager.refresh( parent ) 合并/持久化后,因为调用刷新时集合被初始化。
但在教程中,我从未见过有人使用过这种方法。在 EntityManager 的 JavaDoc 中说过,merge 返回新的托管 bean,而 persist 使引用本身受到管理。我猜托管意味着我已经可以在事务中使用这些集合。为什么集合在创建时没有被初始化?例如,我是否必须在 Parent 的构造函数中自己初始化它们?
我想知道,如果我做错了什么,或者在我创建了一个新的 Parent 实例之后调用 refresh() 方法是否正确?如果是这样猜我只需要像下面的文章中推荐的那样在持久化和更新之间分开:JPA Implemenentations 并在持久化后刷新新创建的对象?还是应该在我真的需要使用 Collection 时只刷新 Object?
希望您能关注我,如果您有任何建议或解决方案让我清楚(呃)这一点,我将不胜感激。
非常感谢,
梅内
【问题讨论】:
标签: java spring collections transactions