我正在尝试将spring,JSF2和hibernate集成到一个新项目中,但我遇到了延迟加载集合的问题。以下是我的问题的摘要,我试图通过EL(JSF)的ajax / PPR请求来弄清楚我是如何延迟加载(来自hibernate with fetch = Lazy)。
问题是我的视图正在尝试访问应该通过EL延迟加载的集合,但该对象已分离,因为请求已完成(我正在使用opensessioninviewfilter)。那么在使用带有许多短ajax-y请求的PPR时,有没有办法延迟加载数据?
在这个例子中,我试图列出多个域对象,并且在部分页面渲染中,使用视图范围的bean,我想选择一个对象并显示有关它的详细信息并可能更新它。我的申请中的典型信息流如下:
*加载域对象列表并将其填充到p:datatable。域对象存储在View范围的辅助bean的列表中 *当用户点击某个项目进行编辑时,该项目将被加载到支持bean中的变量中,该变量名为workingItem,使用ajax / PPR和viewscoped bean。 *通常,然后将项目加载到对话框中(通常是Primefaces p:对话框),这将再次在ajax中完成。 *这是事情发生的地方。如果域对象具有延迟加载的集合(可能填充p:selectOneMenu),则它总是抛出LazyLoadingException。
所以我的问题是,如何在ajax调用期间访问代理时加载一个延迟加载的集合(我没有机会重新附加分离的对象)。
*我不能使用急切的提取来解决这个问题,对象图非常大,我需要将会话信息复制到其他服务器。
*我正在使用Spring的opensessioninviewfilter,但我认为它不能帮助我(对吧?)
*我的根本问题是,当UI尝试在域对象上提取属性时,我不知道如何将域对象附加到会话以执行延迟加载。
我发现懒惰加载(使用hibernate)非常难以在很多地使用ajax。任何建议,建议都会非常感激!
@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;
}
<?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>
任何帮助或指导都将不胜感激,感谢您提前提供的任何帮助!
谢谢, 卡盘
答案 0 :(得分:0)
您已经回答了自己,您需要再次将实体重新连接到Hibernete / JPA会话。查看What is the proper way to re-attach detached objects in Hibernate?
中的所有评论只需按ID加载实体
em.find(entity.getClass(), entity.getId());
您也可以使用合并方法,但如果同时更改实体,则合并可能会更改您的数据或在使用乐观锁定(版本控制)时抛出异常。所以我不建议使用merge来重新连接。