2

我正在尝试将 spring、JSF2 和 hibernate 集成到一个新项目中,但是我遇到了延迟加载集合的问题。这是我的问题的摘要,我试图弄清楚如何通过来自 EL(JSF)的 ajax/PPR 请求延迟加载(从带有 fetch = Lazy 的休眠中)。

问题是我的视图正在尝试访问应该通过 EL 延迟加载的集合,但由于请求已完成(我正在使用 opensessioninviewfilter),该对象已分离。那么,当使用 PPR 和许多简短的 ajax-y 请求时,有什么方法可以延迟加载数据?

在这种情况下,我试图列出多个域对象,并且在部分页面渲染中,使用视图范围的 bean,我想选择其中一个对象并显示有关它的详细信息并可能更新它。我的应用程序中的典型信息流如下:

*域对象列表被加载并填充到 ap:datatable。域对象存储在 View 范围内的支持 bean 的列表中。
*当用户单击一个项目以对其进行编辑时,该项目被加载到支持 bean 中名为 workingItem 的变量中,该变量使用带有 viewscoped bean 的 ajax/PPR。
*通常,然后项目将被加载到对话框中(通常是 Primefaces p:dialog),这将再次在 ajax 中完成。*这是事情发生故障的地方。如果域对象有一个延迟加载的集合(可能填充 ap:selectOneMenu),它总是抛出一个 LazyLoadingException。

所以我的问题是,如何在 ajax 调用期间访问代理时加载延迟加载的集合(我没有机会重新附加分离的对象)。

*我不能使用急切的获取来解决这个问题,对象图非常大,我需要将会话信息复制到其他服务器。
*我正在使用 Spring 的 opensessioninviewfilter,但我不相信它在这种情况下可以帮助我(对吗?) *我的根本问题是我不知道如何将域对象附加到会话以进行延迟加载当 UI 试图拉取域对象上的属性时。

我发现在大量使用 ajax 的情况下,延迟加载(使用休眠)非常困难。任何建议,建议将不胜感激!

这是我的支持 bean(通用):

@Component
@Scope("view")
public abstract class CrudBean<T extends DomainObject,U extends CrudService> extends AgoraBean     implements Serializable
{
private static final Logger logger = LoggerFactory.getLogger(CrudBean.class);

protected U crudService;

protected T workingItem;
protected List<T> cachedItems;
protected List<T> filteredList;

public abstract String createWorkingItem();

public void setWorkingItem(T item)
{
    workingItem = item;
}

public T getWorkingItem()
{
    return workingItem;
}


public List<T> getAllItems()
{
    if ( cachedItems == null )
    {
        cachedItems = getCrudService().getAllItems();
    }
    return cachedItems;
}

/* Other crud-dy stuff removed */

}

这是我的域对象之一的示例:

@Entity
@Table(name = "sites" )
public class Site implements Serializable, DomainObject {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(updatable = false, nullable = false)
private Long id; 

@Version
private Integer version;

@Column(length=255,nullable=false)
private String name;

@Column(length=25)
private String abbreviation;

@Column(length=100)
private String street;

@Column(length=100)
private String city;

@Column(length=2)
private String locationState;

@Column(length=10)
private String zip;

@Column(length=20)
private String phone;

@Column(length=20)
private String fax;

@Column(length=50)
private String contactEmail;

@Index(name = "idxSitePublished")
private boolean published;

@Index(name = "idxSiteDefault")
private boolean defaultSite;

@ManyToOne
private Header header;

@ManyToMany
@Fetch(FetchMode.SELECT)
@BatchSize(size=5)
@OrderBy("priority ASC")
private List<Script> scripts;

@ManyToMany
@BatchSize(size=5)
@OrderBy("priority ASC")
private List<Style> styles;
}

还有我的 Web.xml

 <?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<context-param>
    <param-name>javax.faces.PROJECT_STAGE</param-name>
    <param-value>Development</param-value>
</context-param>
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/application-context.xml</param-value>
</context-param>    
<context-param>
    <param-name>primefaces.THEME</param-name>
    <param-value>home</param-value>
</context-param>
<servlet>
    <servlet-name>Faces Servlet</servlet-name>
    <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>*.html</url-pattern>
</servlet-mapping>
<session-config>
    <session-timeout>
        60
    </session-timeout>
</session-config>


<!-- Listeners - Spring should come first because we need them for our listener -->
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
    <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<listener>
    <listener-class>net.dupage88.www.servlet.SiteServletContextListener</listener-class>
</listener>

<welcome-file-list>
    <welcome-file>index.html</welcome-file>
</welcome-file-list>
<error-page>
    <exception-type>javax.faces.application.ViewExpiredException</exception-type>
    <location>/public/index.html</location>
</error-page>
<!--<error-page>
    <error-code>404</error-code>
    <location>/public/404.jsf</location>
</error-page>
<error-page>
    <error-code>401</error-code>
    <location>/public/401.jsf</location>
</error-page>
<error-page>
    <error-code>500</error-code>
    <location>/public/500.jsf</location>
</error-page>-->

<!-- For Lazy Loading -->
<filter>
    <filter-name>hibernateFilter</filter-name>
    <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
</filter> 
<filter-mapping> 
    <filter-name>hibernateFilter</filter-name> 
    <url-pattern>/*</url-pattern>
</filter-mapping>

<filter>
    <filter-name>RootRedirectFilter</filter-name>
    <filter-class>net.dupage88.www.filters.RootRedirectFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>RootRedirectFilter</filter-name>
    <url-pattern>/index.html</url-pattern>
</filter-mapping>


<filter>
    <filter-name>ShiroFilter</filter-name>
    <filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>ShiroFilter</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>INCLUDE</dispatcher>
    <dispatcher>ERROR</dispatcher>
</filter-mapping>

<listener>
    <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
</listener>


<filter>
    <filter-name>PrimeFaces FileUpload Filter</filter-name>
    <filter-class>org.primefaces.webapp.filter.FileUploadFilter</filter-class>
</filter>   
<filter-mapping>
    <filter-name>PrimeFaces FileUpload Filter</filter-name>
    <servlet-name>Faces Servlet</servlet-name>
</filter-mapping>
</web-app>

任何帮助或指导将不胜感激,并感谢您提前提供的任何帮助!

谢谢,查克

4

1 回答 1

0

您已经回答了自己,您需要再次将实体重新附加到 Hibernete/JPA 会话。查看在 Hibernate 中重新附加分离对象的正确方法是什么?

只需按 ID 加载实体

em.find(entity.getClass(), entity.getId());

您也可以使用合并方法,但如果同时更改实体,如果您使用乐观锁定(版本控制),合并可能会更改您的数据或抛出异常。所以我不建议使用合并来重新附加。

于 2014-11-07T12:24:26.047 回答