jsf视图在修改后不更新支持bean列表属性

时间:2014-04-11 19:29:07

标签: jsf jsf-2 primefaces

我有一个我无法解决的奇怪问题。我有两个实体DeptDivisionDept必须属于Division。因此,每个depts都有一个Division列表。我还有两个视图dept.xhtmldivision.xhtml来管理这两个实体(CRUD操作)。这两个视图均由DeptManagerDivManager支持,这两个视图都是ViewScoped。

division.xhtml上有一个删除按钮,当所选的Division附加了Dept个实体时,该按钮将被禁用。当我转到dept.xhtml并更改分配给特定Division的{​​{1}}时,Dept上的部门表格会正确更新。但是,当我导航到dept.xhtml时,Division表不会捕获更新。显示最近修改的分区的Depts数的列中的值保留修改前的先前值。这会影响division.xhtml上的DELETE按钮,当它不应该被禁用时。我必须关闭浏览器并在捕获更新之前重新打开它。我相信这不应该是因为我的导航导致每次创建一个新视图,我已经通过一些打印输出验证了。这是我的代码:

division.xhtml

dept.xhtml

<h:body> <ui:composition template="adminTemplate.xhtml"> <ui:define name="content"> <h:form id="form"> <p:dataTable id="dtable" value="#{deptManager.orderedDepts}" var="dept" selectionMode="single" selection="#{deptManager.dept}" rowIndexVar="index" rowKey="#{dept.deptCode}" scrollable="true" scrollHeight="270"> <p:ajax event="rowSelect" listener="#{deptManager.onRowSelect}" update=":form:fields" /> <f:facet name="header">List of Departments</f:facet> <p:column headerText="S/No">#{index+1}</p:column> <p:column headerText="Department Code" sortBy="deptCode">#{dept.deptCode}</p:column> <p:column headerText="Department Name" sortBy="description" >#{dept.description}</p:column> <p:column headerText="Division" sortBy="description" >#{dept.divCode.description}</p:column> <f:facet name="footer">Number of Departments #{deptManager.count}</f:facet> </p:dataTable> <br/><br/> <p:panel header="Create/Modify Dept" toggleable="true" toggleOrientation="vertical"> <p:panelGrid columns="2" id="fields"> <p:outputLabel value="Department Code:"/> <p:inputText value="#{deptManager.dept.deptCode}" disabled="true" /> <p:outputLabel value="Department Description:"/> <p:inputText value="#{deptManager.dept.description}" /> <p:outputLabel value="Department Division"/> <p:selectOneMenu value="#{deptManager.dept.divCode}" converter="omnifaces.SelectItemsConverter"> <f:selectItem itemLabel="Select.." noSelectionOption="true" /> <f:selectItems value="#{divManager.orderedDivs}" itemLabel="#{division.description}" var="division" itemValue="#{division}" /> </p:selectOneMenu> </p:panelGrid> <p:commandButton ajax="true" actionListener="#{deptManager.createNew}" value="NEW" update="@form" /> <p:commandButton ajax="true" actionListener="#{deptManager.deleteDept}" value="DELETE" update="@form" /> <p:commandButton ajax="true" actionListener="#{deptManager.saveDept}" value="SAVE" update="@form" /> </p:panel> </h:form> </ui:define> </ui:composition> </h:body>

DeptManager

@Named @ViewScoped public class DeptManager implements Serializable{ @EJB private DeptFacade service; private Dept dept; private List<Dept> depts; @Inject private DivManager divManager; public DeptManager() { } public DivManager getDivManager() { return divManager; } public void setDivManager(DivManager divManager) { this.divManager = divManager; } @PostConstruct public void Init(){ dept = new Dept(); updateList(); } public void setService(DeptFacade service) { this.service = service; } public Dept getDept() { if(dept == null){ dept = new Dept(); } return dept; } public void updateList(){ depts = service.findOrderedAll("Dept", "deptCode"); } public void setDept(Dept dept) { this.dept = dept; } public int getCount(){ return service.count(); } public List<Dept> getDepts(){ return service.findAll(); } public List<Dept> getOrderedDepts(){ return depts; } public String createNew(){ dept = new Dept(); dept.setDeptCode(""); dept.setDivCode(null); dept.setDescription(""); return ""; } public String saveDept(){ //code to create or edit Dept updateList(); divManager.updateList(); return "dept.xhtml?faces-redirect=true"; } public String deleteDept(){ if (dept.getDeptCode() == null || dept.getDeptCode().isEmpty()){ return "dept"; } service.remove(dept); dept = new Dept(); updateList(); divManager.updateList(); return "dept"; } public String onRowSelect(SelectEvent event) { dept = (Dept) event.getObject(); return ""; } public String navigate(String page){ return page; } }

division.xhtml

<h:body> <ui:composition template="adminTemplate.xhtml"> <ui:define name="content"> <h:form id="form"> <p:dataTable id="dtable" value="#{divManager.orderedDivs}" var="division" selectionMode="single" selection="#{divManager.division}" rowIndexVar="index" rowKey="#{division.divCode}" scrollable="true" scrollHeight="300"> <p:ajax event="rowSelect" listener="#{divManager.onRowSelect}" update=":form:fields" /> <f:facet name="header">List of Divisions</f:facet> <p:column headerText="S/No">#{index+1}</p:column> <p:column headerText="Division Code" sortBy="divCode">#{division.divCode}</p:column> <p:column headerText="Division Name" sortBy="description" >#{division.description}</p:column> <p:column headerText="No Of Depts" >#{division.invDeptList.size()}</p:column> <f:facet name="footer">Number of Divisions: #{divManager.count}</f:facet> </p:dataTable> <br/><br/> <p:panel id="fields" header="Create/Modify Division" toggleable="true" toggleOrientation="vertical"> <p:panelGrid columns="2" > <p:outputLabel value="Division Code:"/> <p:inputText value="#{divManager.division.divCode}" disabled="true" /> <p:outputLabel value="Division Description:"/> <p:inputText value="#{divManager.division.description}" /> </p:panelGrid> <p:commandButton ajax="true" actionListener="#{divManager.createNew}" value="NEW" update="@form" /> <p:commandButton ajax="true" actionListener="#{divManager.deleteDiv}" disabled="#{divManager.division.deptList.size() > 0}" value="DELETE" update="@form" /> <p:commandButton ajax="true" actionListener="#{divManager.saveDiv}" value="SAVE" update="@form" /> </p:panel> </h:form> </ui:define> </ui:composition> </h:body>

DivisionManager

根据我的观察,看起来字段@Named @ViewScoped public class DivManager implements Serializable{ @EJB private DivFacade service; private Div division; private ArrayList<Div> divisions; private boolean newInstance; public DivManager() { } @PostConstruct public void Init(){ newInstance = true; division = new Div(); divisions = new ArrayList<Div>(); updateList(); System.out.println("DivManager bean "+this.toString()+" was created"); } public Div getDivision() { if(division == null){ division = new Div(); } return division; } public void setService(DivFacade service) { this.service = service; } public void updateList(){ divisions.clear(); divisions.addAll(service.findOrderedAll("Div", "divCode")); // Also tried: divisions = service.findOrderedAll("Div", "divCode"); same result } public void setDivision(Div div) { this.division = div; } public int getCount(){ return service.count(); } public List<Div> getDivisions(){ return service.findAll(); } public List<Div> getOrderedDivs(){ if(newInstance){ updateList(); newInstance = false; } return divisions; } public String createNew(){ division = new Div(); division.setDivCode(""); division.setDescription(""); return null; } public String saveDiv(){ //code to modify or create Division updateList(); return "division.xhtml?faces-redirect=true"; } public String deleteDiv(){ if (division.getDivCode() == null || division.getDivCode().isEmpty()){ return null; } service.remove(division); division = new Div(); updateList(); return null; } public String onRowSelect(SelectEvent event) { division = (Div) event.getObject(); return null; } public String navigate(String page){ return page; } } 被缓存,并且当调用divisions时,viewScoped bean DivManager的新实例获得相同的列表,除非会话无效。因此,返回缓存中的相同List of Divisions,而不是在updateList() Bean find上调用Session方法。

有什么可能导致这种情况的想法?非常感谢。

1 个答案:

答案 0 :(得分:0)

经过几天的故障排除后,我发现EntityManager使用的Stateless Session Bean保留了从数据库中检索到的Entities缓存。因此,只要为Session Bean的支持bean分配相同的View,那么Entities将始终返回缓存的副本,这可能不是最新的。< / p>

为了解决这个问题,我在我的支持bean中使用了布尔字段newInstance。只要有人要求获取Entities列表,就会检查此字段。如果newInstance为真,我会遍历所有实体并从数据库中刷新它们。这样,只要访问的View是新的(通过检查{{1}是否验证) } backing bean是新的),调用Viewscoped将导致列表中的updateList被刷新。这是修改后的代码:

Entities

@DivManager public void updateList(){ service.refreshList(divisions); } 服务中,我有方法:

SSB

虽然这解决了这个问题,但如果记录数量很大,我设想会出现性能问题。如果有一种方法只监视自上次调用public void refreshList(List<Div> divisions){ EntityManager em = getEntityManager(); for(Div divison : divisions){ division = em.find(Div.class, division.getDivCode()); em.refresh(division); } } 以来已修改的实体并仅刷新那些实体,则会更好。我正在考虑实施这样的解决方案。

希望这会对某人有所帮助。