@ManyToMany启动LazyInitializationException

时间:2012-11-12 10:17:17

标签: java hibernate jpa many-to-many lazy-evaluation

出于某些测试目的,我试图让JUnit测试抛出LazyInitializationException。

我的情况是我有3个实体

@Entity(name = "Role")
public class Role {
    @LazyCollection(LazyCollectionOption.TRUE)
    @ManyToMany(mappedBy = "roles", fetch=FetchType.LAZY)
    private Set<AppUser> appUsers;
    ...

}

@Entity(name = "Group")
public class Group {
    @LazyCollection(LazyCollectionOption.TRUE)
    @ManyToMany(mappedBy = "groups", fetch=FetchType.LAZY)
    private Set<AppUser> appUsers;
    ...
}

@Entity(name = "AppUser")
public class AppUser {
    @LazyCollection(LazyCollectionOption.TRUE)
    @ManyToMany(fetch= FetchType.LAZY)
    @JoinTable(name = "APPUSER_ROLE", joinColumns = @JoinColumn(name = "USER_ID", referencedColumnName = "ID"), inverseJoinColumns = @JoinColumn(name = "ROLE_ID", referencedColumnName = "ID"))
    private Set<Role> roles;
    ...

    @LazyCollection(LazyCollectionOption.TRUE)
    @ManyToMany(fetch= FetchType.LAZY)
    @JoinTable(name = "APPUSER_GROUP", joinColumns = @JoinColumn(name = "USER_ID", referencedColumnName = "ID"), inverseJoinColumns = @JoinColumn(name = "GROUP_ID", referencedColumnName = "ID"))
    private Set<Group> groups;
    ...

} 

我生成了一些测试数据,其中所有这三个都正确地保存在具有关系的DB中。然后我提交了交易。

然后我尝试使用相同的测试方法来读取Role(基于id),但我也得到了所有其他相关实体的读取(似乎是急切地加载)。为什么会这样?我怎样才能来LazyInitializationException

编辑:好的我对一般描述不感兴趣,而是我需要一个代码示例,因为我不能在我的情况下启动它。一般说明并不能解决我的问题。

2 个答案:

答案 0 :(得分:3)

  

如何进入LazyInitializationException?

当你有:

  1. 延迟加载的实体成员(例如OneToMany或ManyToMany)
  2. 没有活动事务(实体已分离)
  3. 该成员尚未加载
  4. 您尝试访问实体成员,这应该触发延迟加载,但由于实体已分离,因此无法实现

答案 1 :(得分:0)

问题在于,即使我在我的测试方法中提交了事务,我也必须关闭EntityManager并再次重新打开它以在我的设置中触发LazyInitializationException

最后,我最终得到了以下实体代码:

@Entity(name = "Role")
public class Role {
    @ManyToMany(mappedBy = "roles")
    private Set<AppUser> appUsers;
    ...

}

@Entity(name = "Group")
public class Group {
    @ManyToMany(cascade = {CascadeType.PERSIST})
    @JoinTable(name = "GROUP_APPUSER", joinColumns = @JoinColumn(name = "GROUP_ID", referencedColumnName = "ID"), inverseJoinColumns = @JoinColumn(name = "USER_ID", referencedColumnName = "ID"))
    private Set<AppUser> appUsers;
    ...
}

@Entity(name = "AppUser")
public class AppUser {
    @ManyToMany(cascade = {CascadeType.PERSIST})
    @JoinTable(name = "APPUSER_ROLE", joinColumns = @JoinColumn(name = "USER_ID", referencedColumnName = "ID"), inverseJoinColumns = @JoinColumn(name = "ROLE_ID", referencedColumnName = "ID"))
    private Set<Role> roles;
    ...

    @ManyToMany(mappedBy = "appUsers")
    private Set<Group> groups;
    ...

} 

所以而不是:

Group <- AppUser -> Role

我有:

Group -> AppUser -> Role

即使是艰难也没必要,因为已经发生了1.懒惰负载(Group -> AppUser)的懒惰问题。

测试代码本身,最​​重要的部分是:

em.getTransaction().begin();
em.persist(group);
em.getTransaction().commit();
em.close();

// reinit em
...

// load group from DB and afterwards close em
em.close();
...
// following throws LazyInitializationException :)
group.getAppUsers().iterator().next();