我有一些“类别”模型,该模型被组织为邻接表。因此,当我添加新列表时,我会格式化当前列表,使其具有可见的层次结构。为此,我使用Omnifaces ViewScoped bean。加载数据后,我将其格式化并显示在selectOneMenu中。当我添加具有父项的新类别时,我将重定向到类别列表。如果我再次打开表单页面,它不会显示新的层次结构,但是会将新类别放在最后,就好像它没有父级一样。例如,如果我重新启动服务器并再次加载页面,则应显示它。
所以我的问题是,既然我显然做错了,如何正确刷新它。
form.xhtml
<?xml version="1.0" encoding="UTF-8"?>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
template="#{adminConfig.templatePath}"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<ui:define name="title">#{categoryFormMB.title}</ui:define>
<ui:define name="description"></ui:define>
<ui:define name="body">
<f:metadata>
<f:viewParam name="id" value="#{categoryFormMB.id}" converter="javax.faces.Long"/>
<f:event type="preRenderView" listener="#{categoryFormMB.initForm()}"/>
</f:metadata>
<div class="row">
<div class="col-md-6">
<p:panel styleClass="box box-primary">
<h:form styleClass="form-horizontal">
<div class="form-group ui-flat">
<p:outputLabel
for="name"
value="#{label.categoryName}"
styleClass="control-label col-md-4"/>
<div class="col-md-8">
<p:inputText
id="name"
value="#{categoryFormMB.category.name}"
styleClass="form-control"
required="true" />
</div>
</div>
<div class="form-group ui-flat">
<p:outputLabel
for="slug"
value="#{label.categorySlug}"
styleClass="control-label col-md-4"/>
<div class="col-md-8">
<p:inputText
id="slug"
value="#{categoryFormMB.category.slug}"
styleClass="form-control"
required="true" />
</div>
</div>
<div class="form-group ui-flat">
<p:outputLabel
for="parent"
value="#{label.parentCategory}"
styleClass="control-label col-md-4"/>
<div class="col-md-8">
<p:selectOneMenu
value="#{categoryFormMB.category.parent}"
id="parent"
converter="categoryConv">
<f:selectItem
itemLabel="#{label.noParent}"
itemValue=""/>
<f:selectItems
value="#{categoryFormMB.formattedList}"
var="category"
itemValue="#{category}"
itemLabel="#{category.name}"/>
</p:selectOneMenu>
</div>
</div>
<div class="form-group ui-flat">
<p:outputLabel
for="description"
value="#{label.categoryDescription}"
styleClass="control-label col-md-4"/>
<div class="col-md-8">
<p:inputTextarea
id="description"
value="#{categoryFormMB.category.description}"
styleClass="form-control"/>
</div>
</div>
<div class="form-group ui-flat">
<p:outputLabel
for="title-tag"
value="#{label.titleTag}"
styleClass="control-label col-md-4"/>
<div class="col-md-8">
<p:inputText
id="title-tag"
value="#{categoryFormMB.category.titleTag}"
styleClass="form-control"/>
</div>
</div>
<div class="form-group ui-flat">
<p:outputLabel
for="description-tag"
value="#{label.descriptionTag}"
styleClass="control-label col-md-4"/>
<div class="col-md-8">
<p:inputTextarea
id="description-tag"
value="#{categoryFormMB.category.descriptionTag}"
styleClass="form-control"/>
</div>
</div>
<div class="form-group">
<div class="col-md-4"></div>
<div class="col-md-8">
<div class="pull-right">
<p:commandButton
value="#{label.saveCategory}"
ajax="false"
rendered="#{ ! categoryFormMB.editing}"
action="#{categoryFormMB.save()}"
styleClass="btn btn-success btn-flat"
icon="fa fa-floppy-o"/>
<p:commandButton
value="#{label.updateCategory}"
ajax="false"
rendered="#{categoryFormMB.editing}"
action="#{categoryFormMB.update()}"
styleClass="btn btn-success btn-flat"
icon="fa fa-floppy-o"/>
<p:commandButton
value="#{label.cancel}"
action="#{categoryFormMB.close()}"
styleClass="btn btn-danger btn-flat"
ajax="false"
icon="fa fa-times"
immediate="true"/>
</div>
</div>
</div>
</h:form>
<p:messages
globalOnly="false"
showDetail="true"
showSummary="false"
showIcon="true" />
</p:panel>
</div>
</div>
</ui:define>
</ui:composition>
CategoryFormMB
package com.github.cvetan.bookstore.mb.category;
import static com.github.adminfaces.template.util.Assert.has;
import com.github.cvetan.bookstore.model.Category;
import com.github.cvetan.bookstore.sb.category.CategorySBLocal;
import com.github.cvetan.bookstore.util.Redirector;
import com.github.cvetan.bookstore.util.StringRepeater;
import java.util.ArrayList;
import java.util.List;
import javax.ejb.EJB;
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;
/**
*
* @author cvetan
*/
@Named(value = "categoryFormMB")
@RequestScoped
public class CategoryFormMB {
@EJB
private CategorySBLocal categorySB;
private List<Category> list;
private List<Category> formattedList;
private String title;
private Integer id;
private boolean editing;
private Category category;
private String message;
/**
* Creates a new instance of CategoryFormMB
*/
public CategoryFormMB() {
}
public CategorySBLocal getCategorySB() {
return categorySB;
}
public void setCategorySB(CategorySBLocal categorySB) {
this.categorySB = categorySB;
}
public List<Category> getList() {
return list;
}
public void setList(List<Category> list) {
this.list = list;
}
public List<Category> getFormattedList() {
return formattedList;
}
public void setFormattedList(List<Category> formattedList) {
this.formattedList = formattedList;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public boolean isEditing() {
return editing;
}
public void setEditing(boolean editing) {
this.editing = editing;
}
public Category getCategory() {
return category;
}
public void setCategory(Category category) {
this.category = category;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public void initForm() {
formattedList = new ArrayList<>();
getListFromDB();
formatList(list, 0);
if (has(id)) {
// TODO
} else {
title = "New category";
editing = false;
category = new Category();
message = "Category has been saved.";
}
}
private void getListFromDB() {
list = categorySB.getAll();
}
private void formatList(List<Category> list, int level) {
for (Category c: list) {
if (formattedList.contains(c)) {
continue;
}
c.setName(StringRepeater.repeat(" - ", level) + c.getName());
formattedList.add(c);
if ( ! c.getChildCategories().isEmpty()) {
formatList(c.getChildCategories(), level + 1);
}
}
}
public String save() {
try {
categorySB.save(category);
return Redirector.redirectWithInfo("Category has been saved.", "/admin/category-list.xhmtl?faces-redirect=true");
} catch (Exception ex) {
return Redirector.redirectWithError(ex.getMessage(), "/admin/category-form.xhtml?faces-redirect=true");
}
}
}
CategorySB(EJB)
package com.github.cvetan.bookstore.sb.category;
import com.github.cvetan.bookstore.model.Category;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
/**
*
* @author cvetan
*/
@Stateless
public class CategorySB implements CategorySBLocal {
@PersistenceContext (unitName = "BookstorePU")
private EntityManager entityManager;
@Override
public List<Category> getAll() {
return entityManager.createNamedQuery("Category.findAll").getResultList();
}
@Override
public void save(Category category) {
entityManager.persist(category);
}
@Override
public Category getById(int id) {
Query query = entityManager.createNamedQuery("Category.findById");
query.setParameter("id", id);
Category category = (Category) query.getSingleResult();
return category;
}
@Override
public void update(Category category) {
}
@Override
public void delete(int id) {
Category category = entityManager.find(Category.class, id);
entityManager.remove(category);
}
}
类别实体
package com.github.cvetan.bookstore.model;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.PrePersist;
import javax.persistence.PreUpdate;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
/**
*
* @author cvetan
*/
@Entity
@Table(name = "categories")
@XmlRootElement
@NamedQueries({
@NamedQuery(name = "Category.findAll", query = "SELECT c FROM Category c")
, @NamedQuery(name = "Category.findById", query = "SELECT c FROM Category c WHERE c.id = :id")
, @NamedQuery(name = "Category.findByName", query = "SELECT c FROM Category c WHERE c.name = :name")
, @NamedQuery(name = "Category.findBySlug", query = "SELECT c FROM Category c WHERE c.slug = :slug")
, @NamedQuery(name = "Category.findByDescription", query = "SELECT c FROM Category c WHERE c.description = :description")
, @NamedQuery(name = "Category.findByTitleTag", query = "SELECT c FROM Category c WHERE c.titleTag = :titleTag")
, @NamedQuery(name = "Category.findByDescriptionTag", query = "SELECT c FROM Category c WHERE c.descriptionTag = :descriptionTag")
, @NamedQuery(name = "Category.findByCreatedAt", query = "SELECT c FROM Category c WHERE c.createdAt = :createdAt")
, @NamedQuery(name = "Category.findByUpdatedAt", query = "SELECT c FROM Category c WHERE c.updatedAt = :updatedAt")})
public class Category implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Basic(optional = false)
@Column(name = "id")
private Integer id;
@Basic(optional = false)
@NotNull
@Size(min = 1, max = 255)
@Column(name = "name")
private String name;
@Basic(optional = false)
@NotNull
@Size(min = 1, max = 255)
@Column(name = "slug")
private String slug;
@Size(max = 255)
@Column(name = "description")
private String description;
@Size(max = 255)
@Column(name = "title_tag")
private String titleTag;
@Size(max = 255)
@Column(name = "description_tag")
private String descriptionTag;
@Basic(optional = false)
@NotNull
@Column(name = "created_at")
@Temporal(TemporalType.TIMESTAMP)
private Date createdAt;
@Column(name = "updated_at")
@Temporal(TemporalType.TIMESTAMP)
private Date updatedAt;
@OneToMany(mappedBy = "parent", fetch = FetchType.LAZY)
private List<Category> childCategories;
@JoinColumn(name = "parent", referencedColumnName = "id")
@ManyToOne
private Category parent;
public Category() {
}
public Category(Integer id) {
this.id = id;
}
public Category(Integer id, String name, String slug, Date createdAt) {
this.id = id;
this.name = name;
this.slug = slug;
this.createdAt = createdAt;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSlug() {
return slug;
}
public void setSlug(String slug) {
this.slug = slug;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getTitleTag() {
return titleTag;
}
public void setTitleTag(String titleTag) {
this.titleTag = titleTag;
}
public String getDescriptionTag() {
return descriptionTag;
}
public void setDescriptionTag(String descriptionTag) {
this.descriptionTag = descriptionTag;
}
public Date getCreatedAt() {
return createdAt;
}
public void setCreatedAt(Date createdAt) {
this.createdAt = createdAt;
}
public Date getUpdatedAt() {
return updatedAt;
}
public void setUpdatedAt(Date updatedAt) {
this.updatedAt = updatedAt;
}
@XmlTransient
public List<Category> getChildCategories() {
return childCategories;
}
public void setChildCategories(List<Category> childCategories) {
this.childCategories = childCategories;
}
public Category getParent() {
return parent;
}
public void setParent(Category parent) {
this.parent = parent;
}
@Override
public int hashCode() {
int hash = 0;
hash += (id != null ? id.hashCode() : 0);
return hash;
}
@Override
public boolean equals(Object object) {
if (!(object instanceof Category)) {
return false;
}
Category other = (Category) object;
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
return false;
}
return true;
}
@Override
public String toString() {
return name;
}
@PrePersist
public void setCreatedAt() {
createdAt = new Date();
}
@PreUpdate
public void setUpdatedAt() {
updatedAt = new Date();
}
}
答案 0 :(得分:0)
JPA / EclipseLink端有缓存,我不知道。当我使用entityManager.getEntityManagerFactory().getCache().evictAll();
清除缓存时,它将刷新数据。所以问题不在豆子上或不在其范围内。