如何在JavaEEWeb应用程序中使用惰性实体加载?

如何在JavaEEWeb应用程序中使用惰性实体加载?,java,web-applications,jpa,jakarta-ee,persistence,Java,Web Applications,Jpa,Jakarta Ee,Persistence,在我的Web应用程序中,我加载了许多实体,以便在表中显示它们。我可以单击每个tablerow以获取有关特定实体的“详细信息” 对我来说,很明显,不加载tableview的“详细信息”,但只有当有人想查看它时(单击一行) 仅为这些字段设置(fetch=FetchType.LAZY)不起作用,因为实体在获取后会分离,在我的WebApp中会出现空值 好的,接下来我要做的就是通过将fetch操作放入带有扩展PersistenceContext的StatefulSessionBean中来防止分离 @Per

在我的Web应用程序中,我加载了许多实体,以便在表中显示它们。我可以单击每个tablerow以获取有关特定实体的“详细信息”

对我来说,很明显,不加载tableview的“详细信息”,但只有当有人想查看它时(单击一行)

仅为这些字段设置
(fetch=FetchType.LAZY)
不起作用,因为实体在获取后会分离,在我的WebApp中会出现空值

好的,接下来我要做的就是通过将fetch操作放入带有扩展PersistenceContext的StatefulSessionBean中来防止分离

@PersistenceContext(unitName=“unitName”,type=PersistenceContextType.EXTENDED)
私有实体管理器em

这可以工作,但也会产生奇怪的副作用(最明显的是在某些页面重新加载时出现
ConcurrentAccessExceptions
,我可以通过设置一些openjpa属性来修复) servlet需要自己的获取EJB,因为它们不与SFSB合作。大多数事情似乎都很顺利,但我期待着s**t很快就会启动

我的问题是我是否走错了方向。这一切对我来说似乎有点尴尬。在没有真正的对话时使用有状态bean,用户可以随时离开,而不触发某些@Remove方法。当用户长时间离开时,必须在超时时关闭资源,导致许多未使用的SFSB打开

一般来说,懒散加载是一件非常简单的事情,但在JavaEE环境中,我不知道如何做到这一点。最佳做法是什么

多谢各位

更新

这就是我现在手动获取字段的方式

@SuppressWarnings("unchecked")
public <T extends BasicEntity> T loadLazyField(T entity, String field) throws NoSuchFieldException {
    if (!typeHasField(entity.getClass(), field)) {
        throw new NoSuchFieldException(entity.getClass().getSimpleName() + " has no field called " + field);
    }

    String queryString = String.format("SELECT x FROM %s x WHERE x = :entity LEFT JOIN FETCH x.%s", entity.getClass()
            .getSimpleName(), entity, field);
    Query q = em.createQuery(queryString);
    q.setParameter("entity", entity);
    return (T) q.getSingleResult();
}

@SuppressWarnings("unchecked")
public <T extends BasicEntity> T loadLazyFields(T entity, String[] fields) throws NoSuchFieldException {
    String queryString = String.format("SELECT x FROM %s x WHERE x = :entity", entity.getClass().getSimpleName());

    for (String field : fields) {
        if (!typeHasField(entity.getClass(), field)) {
            throw new NoSuchFieldException(entity.getClass().getSimpleName() + " has no field called " + field);
        }
        queryString += String.format(" LEFT JOIN FETCH x.%s", field);
    }
    Query q = em.createQuery(queryString);
    q.setParameter("entity", entity);
    return (T) q.getSingleResult();

}

private boolean typeHasField(Class<?> type, String field) {
    try {
        type.getDeclaredField(field);
        return true;
    } catch (NoSuchFieldException e) {
        return false;
    }
}
@SuppressWarnings(“未选中”)
公共T loadLazyField(T实体,字符串字段)抛出NoSuchFieldException{
如果(!typeHasField(entity.getClass(),field)){
抛出新的NoSuchFieldException(entity.getClass().getSimpleName()+“没有名为“+字段”的字段);
}
String queryString=String.format(“从%s x中选择x,其中x=:entity LEFT JOIN FETCH x.%s”,entity.getClass()
.getSimpleName(),实体,字段);
Query q=em.createQuery(queryString);
q、 setParameter(“实体”,实体);
返回(T)q.getSingleResult();
}
@抑制警告(“未选中”)
公共T loadLazyFields(T实体,字符串[]字段)抛出NoSuchFieldException{
String queryString=String.format(“从%s x中选择x,其中x=:entity”,entity.getClass().getSimpleName());
用于(字符串字段:字段){
如果(!typeHasField(entity.getClass(),field)){
抛出新的NoSuchFieldException(entity.getClass().getSimpleName()+“没有名为“+字段”的字段);
}
queryString+=String.format(“左联合提取x.%s”,字段);
}
Query q=em.createQuery(queryString);
q、 setParameter(“实体”,实体);
返回(T)q.getSingleResult();
}
私有布尔类型HasField(类类型,字符串字段){
试一试{
类型。getDeclaredField(字段);
返回true;
}捕获(无此字段例外){
返回false;
}
}

您需要一个名为“在视图中打开会话”的设计模式,使持久性会话在页面呈现阶段保持打开状态。此功能由Seam等集成框架提供


我不确定JSF2是否支持这一点,因为Seam2的许多特性都转移到了JavaEE6。无论如何,你应该看看Seam(尽管Seam3很难运行)。

我很确定你给我指明了一个完全正确的方向。但我使用的是Websphere AS 7.5(openJPA、ee5、jsf1.2),如果不进行大量配置(例如更改类装入器顺序),Hibernates OSiV和Seam都不可用。我仍在尝试使用WAS运行Seam,如果这不起作用,可能需要手动实现该模式。(如果我能在某个地方找到一个HowTo,那就太好了)我也会在这里发布我的结果和解决方案。非常感谢你的提示。