Glassfish中的LAZY关系实例化问题

时间:2012-12-11 19:10:50

标签: jpa ejb glassfish-3

我有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

        }

                    ...

有关代码的任何建议吗? 遗憾的是,论坛上发布的类似问题对我无效。

2 个答案:

答案 0 :(得分:4)

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

在许多情况下,只需在JPA Session中的懒惰加载列表上调用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;
}

答案 1 :(得分:0)

我制作了获取类型EAGER,这是我弄清楚如何避免错误的唯一方法:

@OneToMany(..., fetch=EAGER, mappedBy = "...")