Spring @Transactional - 在持久化/合并后使用集合

时间:2010-11-19 14:01:38

标签: java spring collections transactions

我在我的应用程序中使用Spring和JPA,但最近我对使用DomainObjects的集合感到有些困惑。

例如:

想象一下,我们有两个表:Parent和Child。父母可以有几个孩子(@OneToMany),孩子只能有一个孩子(@ManyToOne)。我使用Spring来处理我的ServiceLayer中的事务上下文(不是Dao - 工作单元模式),它在context-application.xml中由aop:config配置。子集合标记为LazyLoading Collection。到目前为止,一切都很好。

现在的问题如下:

我的服务中需要一个方法,它创建一个新的Parent并在同一个事务中调用另一个方法,用新创建的Parent进行一些计算。在这些计算中,我必须调用parent.getChildren()。显然这应该返回一个空Set,因为新的Parent在创建时没有任何Children,但由于某种原因我得到'null'而不是空集,这导致NullpointerException

要创建父级,我尝试了以下EntityManager方法:

  1. 使用entityManager.persist(parent) - 没有工作,创建后集合为空。
  2. 使用entityManager.merge(parent)并返回父的新托管实例 - 具有相同的结果。
  3. 两者都导致了空集。但我很确定,这些调用是在同一个事务中,因为在事务之外,我会收到一个LazyLoadingException(而不是NullPointer),此时(afaik)正确。另一方面,使用已经存在的parentManager.findById()的父项导致了一个现有的集合(这意味着它的工作方式与预期的一样)。为了解决这个问题,我尝试了几种方法,直到找到一个有效的方法:

    合并/持久化后

    entityManager.refresh(parent),因为在调用refresh时集合会被初始化。

    但在教程中我从未见过这种方法正在被使用。在EntityManager的JavaDoc中,已经说过,合并返回新的托管bean,而persist使引用本身得到管理。我猜想托管意味着,我已经可以在事务中使用这些集合了。为什么集合在创建时没有被初始化?我是否必须在Parent的构造函数中自己初始化它们?

    我想知道,如果我做错了什么,或者在创建新的Parent实例后调用refresh()是正确的方法吗?如果这样猜测我只需要在持久化和更新之间分开,就像在下面的文章中建议的那样:JPA Implemenentations并在持久化后刷新新创建的对象?或者,当我真的需要使用Collection时,我应该刷新Object吗?

    希望你能跟随我,我希望有任何建议或解决方案让我明白(呃)。

    非常感谢,
    ymene

2 个答案:

答案 0 :(得分:4)

您是否初始化了收藏字段?

@OneToMany
private Set<Foo> foos = new HashSet<Foo>();

而不是

@OneToMany
private Set<Foo> foos;

因为后者当然会抛出NPE。

答案 1 :(得分:0)

尝试在父类中使用CascadeType.ALL。

@OneToMany(cascade = CascadeType.ALL)
public List<Child> getChildren() {
  return children;
}

其次使用OpenSessionInViewFilter。这将确保您甚至可以从视图中调用parent.getChildren(),并且hibernate会话保持打开状态,直到响应被发回。以下是如何在web.xml中配置它

<filter>
 <filter-name>OpenSessionInViewFilter</filter-name>
 <filter-class>com.isavera.hibernate.OpenSessionFilter</filter-class>
   <init-param>
     <param-name>singleSession</param-name>
 <param-value>false</param-value>
   </init-param>
 </filter>

<filter-mapping>
 <filter-name>OpenSessionInViewFilter</filter-name>
 <url-pattern>/*</url-pattern>
</filter-mapping>

希望这有帮助