2

我有 Glassfish 3.1 和 oneToMany 关系。不断报错:

Exception Description: An attempt was made to traverse a relationship using indirection that had a null Session. This often occurs when a n entity with an uninstantiated LAZY relationship is serialized and that lazy relationship is traversed after serialization. To avoid this issue, ins tantiate the LAZY relationship prior to serialization.

用户实体。

@Entity
@Table(name="USERS")
public class User implements Serializable
{
    private static final long serialVersionUID = -8636046618352460140L;
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private long userId;
    private String userName;
    private int userAge;
    private double latitude;
    private double longitude;

    public User() {

    }

// getters & setters
}

集团实体

@Entity
@Table(name="USERS_GROUPS")
public class Group implements Serializable
{
    private static final long serialVersionUID = -9124043819358665396L;
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private long groupId;
    private String groupName;
    @OneToMany(cascade=CascadeType.PERSIST, fetch=FetchType.EAGER)
    @JoinTable(name="JOIN_USER_GROUP",
            joinColumns={@JoinColumn(name="groupId")},
            inverseJoinColumns={@JoinColumn(name="userId")})
    private List<User> users = null;

    public Group() {

    }
// getters & setters
}

还有豆子:

@PersistenceContext
private EntityManager em;
    ...
public Group searchGroup(String groupName) {
    Query q = em.createQuery("SELECT g FROM Group g " +
            "WHERE g.groupName = :name");
    q.setParameter("name", groupName);
    Group result = (Group) q.getResultList().get(0);
    result.getUsers().size(); // << LAZY instantiation
    return result;
}
// NOT TESTED
public void updateGroup(Group group) 
{
    em.merge(group);
}

    ... 

客户端测试驱动程序:

public static void main(String[] args) 
{
    try
    {
        Context jndi = new InitialContext();

        GroupManagementService service = (GroupManagementService)
                  jndi.lookup("java:global/GroupsManagement/GroupManagementServiceImp");

        User u = new User("John", 20, 54.04, 0.4);

                    // the group home is already in a database
        Group group = service.searchGroup("home");

                    group.getUsers().add(u); // << ERROR here
                    service.updateGroup(group);

                    /* IF do this */
        List<User> l = group.getUsers();
        if(l == null)
            System.out.println("NULL");
        else {
            System.out.println("SIZE: "+l.size()); // << ERROR here

        }

                    ...

关于代码的任何建议?论坛上发布的类似问题,不幸的是对我不起作用。

4

2 回答 2

4

对 group.getUsers() 的调用导致抛出此异常,因为用户列表从未填充到 JPA 会话中。必须在退出 JPA Session 范围之前遍历惰性关系以避免异常。

在许多情况下,只需在 JPA 会话中对延迟加载的列表调用 size() 即可解决异常。

public Group searchGroup(String groupName) {
    Query q = em.createQuery("SELECT g FROM Group g " +
        "WHERE g.groupName = :name");
    q.setParameter("name", groupName);
    Group result = (Group) q.getResultList().get(0);
    result.getUsers().size(); // << LAZY instantiation
    return result;
}

但是,在某些情况下 .size() 本身无法解决问题。我发现它在发生这种情况时与 JOIN FETCH 结合使用。

public Group searchGroup(String groupName) {
    Query q = em.createQuery("SELECT g FROM Group g LEFT JOIN FETCH g.users " +
        "WHERE g.groupName = :name");
    q.setParameter("name", groupName);
    Group result = (Group) q.getResultList().get(0);
    result.getUsers().size(); // << LAZY instantiation
    return result;
}

执行 JOIN FETCH 的另一种方法:

public Group searchGroup(String groupName) {
    Query q = em.createQuery("SELECT g FROM Group g " +
        "WHERE g.groupName = :name");
    q.setParameter("name", groupName);
    q.setHint("eclipselink.left-join-fetch","g.users"); // << join fetch as hint
    Group result = (Group) q.getResultList().get(0);
    result.getUsers().size(); // << LAZY instantiation
    return result;
}
于 2012-12-11T19:35:06.693 回答
0

我将获取类型设置为 EAGER,这是我弄清楚如何避免错误的唯一方法:

@OneToMany(..., fetch=EAGER, mappedBy = "...")
于 2015-05-09T20:37:15.220 回答