抛开编辑,
这里的问题是您的列表在每次排序时都会从实体中刷新。由于每次在排序后刷新 UI 时设置框架的方式,您将拉出一个新列表。
基本上你看到了->(这不准确,它是它正在做的事情的草图)
UI -> sort(myBean.getList());
UI -> redraw(myBean.getList());
看这意味着您有两个不同的引用,您对引用 #1 进行排序,然后丢弃它并获取新的渲染引用。因此,您的排序不起作用。
解决方案是使用排序后可以引用的成员。这不是一个大问题,因为您可以使用 View Scope 而不是 Session 或 Request 范围。内存方面,你的想法是对的,但你可能过度优化,因为你正在失去功能。
简而言之,修复是->
@ViewScoped
public class MyBean
{
private List<T> myList;
public List<T> getMyList()
{
if(myList != null)
return myList;
myList = Service.getMyList();
return myList;
}
}
因为您现在可以对列表进行排序并维护引用,所以该组件将起作用。如果您确实遇到了内存问题,那么您可以开始沿着优化路径走下去,即在服务端执行排序,创建一个基于调用排序的新列表,然后在请求范围内返回。Primefaces 允许您这样做,但请先尝试简单的方法。
//-----------回应吹毛求疵(因为我今天有时间,很有趣……)--------/
我不是想对你怀有敌意。如果您处于那种规模,为什么不实现一个自定义组件来根据您的内存负载来处理它?显然,实体和数据库本身之间存在抽象,因此请实现自定义排序,以便您的getData()
方法能够返回正确的排序集,而不是维护的引用。显然 Primefaces(和大多数 JSF 实现)维护引用(有状态),因此您需要一个低内存解决方案。
它可能看起来像 ->
@RequestScoped
public class LessMemoryBean
{
public List<T> getList()
{
StatefulBean state = getStatefulBean();
//Some switch/case or other method of determining state
return service.getSortedList(state.getState()); //I like hashmaps, but anything could work.
}
}
@ViewScoped
public class StatefulBean
{
private HashMap<String, Boolean> state;
public void sortField(String key, boolean sortBy)
{
state.put(key, sortBy); //Construct the proper query via the keys provided
}
}
//XHTML
<p:dataTable value="#{lessMemoryBean.data}">
<!-- Whatever you need -->
<p:column>
<f:facet name="header">
<p:commandButton
//Do whatever control method you want for sorting and setting booleans
/>
</f:facet>
</p:column>
....
因为您使用的是对 RequestScoped bean 的引用,并且该 bean 引用了 ViewScoped,所以您的列表存储在请求中(尽快处理),但表的状态是分开的。显然,这不是开箱即用的,Primefaces 支持一些听众,但您需要更深入地挖掘 (RTFM) 以查看您的选择。此外,它是开源的,因此您可以简单地扩展表以使用侦听器作为选项,而不是简单的链接到Collection
.
你说的是优化,在我看来,这意味着你需要做很多额外的工作。有它(我个人会使用标准数据表或在这种情况下实现我自己的复合组件。最多 1-2 天不会有那么多工作)。