在h:dataTable中更新后,更改未反映在JPA实体中 [英] Changes not reflected in JPA entities after updating in h:dataTable

查看:64
本文介绍了在h:dataTable中更新后,更改未反映在JPA实体中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Eclipse和Glassfish 3.0.尽管我之前做过类似的事情,但这项技术还很新.很简单,确实有一个绑定到支持bean的数据表.我已经介绍过的添加方法和删除方法-问题在于我正在调用的更新方法.我似乎看不到组件(HtmlInputText)中发生的更改,不必介意将数据传递回表中.

I am working with Eclipse and Glassfish 3.0. Pretty new to this technology although I have done similar things before. Very simple really got a datatable bound to a backing bean. Add methods and remove methods i have covered - the problem lies with the update method I am calling. I cannot seem to see the changes being picked up in the component (HtmlInputText) never mind passing the data back to the table.

我的数据表代码如下(和jsf页)

My code for the data table is below (and the jsf page)

<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">

<f:loadBundle basename="resources.application" var="msg"/>

<head>
    <title><h:outputText value="#{msg.welcomeTitle}" /></title>
</head>
<body>
 <h:form id="mainform">

  <h:dataTable var="row"  border="0" value="#{beanCategory.collection}" binding="#{beanCategory.datatable}">

    <f:facet name="header">
        <h:outputText value="Categories"/>
    </f:facet>
    <h:column>
        <f:facet name="header">
            <h:outputText value="Description"/>
        </f:facet> 

            <h:inputText id="input1" value="#{row.description}" valueChangeListener="#{row.inputChanged}"/>


        </h:column>
    <h:column>
        <f:facet name="header">
            <h:outputText value="Id"/>
        </f:facet>
        <h:outputText id="id" value="#{row.id}"/>
    </h:column>
    <h:column>
            <h:commandButton value="Delete" type="submit" action="#{beanCategory.remove}">

                <f:setPropertyActionListener target="#{beanCategory.selectedcategory}" value="#{row}"/>
            </h:commandButton>
            <h:commandButton value="Save" action="#{beanCategory.update}"
                >
                <f:setPropertyActionListener
                    target="#{beanCategory.selectedcategory}" value="#{row}" />

            </h:commandButton>
        </h:column>
</h:dataTable>

<h:inputText id="text1"></h:inputText>  <h:commandButton action="#{beanCategory.addCategory}" value="Add" type="submit" id="submitbutton">

</h:commandButton>
<br/><br/>
Messages    

<h:messages></h:messages><br /><br />

</h:form>   
 </body>
</html>

Backing Bean在这里

Backing Bean is here

package net.bssuk.timesheets.controller;

import java.io.Serializable;

import java.util.List;

import javax.faces.component.UIInput;
import javax.faces.component.html.HtmlDataTable;
import javax.faces.context.FacesContext;

import javax.persistence.*;

import net.bssuk.timesheets.model.Category;

@javax.inject.Named("beanCategory")
@javax.enterprise.context.SessionScoped

public class BeanCategory implements Serializable {

private List<Category> collection;
private EntityManagerFactory emf;
private EntityManager em;
private int selectedid;
private Category selectedcategory;
private HtmlDataTable datatable;

private static final long serialVersionUID = 1L;

public BeanCategory() {
    // TODO Auto-generated constructor stub

    System.out.println("Bean Constructor");

}

public String addCategory() {
    try {
        this.emf = Persistence.createEntityManagerFactory("timesheets1");
        System.out.println("Changed - Now attempting to add");
        System.out.println("Ready to do cateogory");
        Category category = new Category();

        FacesContext context = FacesContext.getCurrentInstance();
        UIInput input = (UIInput) context.getViewRoot().findComponent(
                "mainform:text1");

        String value = input.getValue().toString();
        if (value != null) {
            category.setDescription(input.getValue().toString());
        } else {
            category.setDescription("Was null");
        }
        this.em = this.emf.createEntityManager();
        EntityTransaction tx = em.getTransaction();
        tx.begin();
        em.persist(category);
        tx.commit();
        em.close();
        emf.close();
        // return "index.xhtml";
    } catch (Exception e) {
        e.printStackTrace();
    }
    return "return.html";
}

public String remove() {
    try {
        this.emf = Persistence.createEntityManagerFactory("timesheets1");
        System.out.println("Getting Collection");
        this.em = this.emf.createEntityManager();

        FacesContext context = FacesContext.getCurrentInstance();

        System.out.println("Number found is " + this.selectedid);

        if (selectedcategory != null) {

            System.out.println("removing "+selectedcategory.getId()+" - " +selectedcategory.getDescription());
            EntityTransaction tx = em.getTransaction();
            tx.begin();
            System.out.println("Merging..");
            this.em.merge(selectedcategory);
            System.out.println("removing...");
            this.em.remove(selectedcategory);
            tx.commit();
            em.close();
            emf.close();
        }else{
            System.out.println("Not found");
        }
        return "index.xhtml";
    } catch (Exception e) {
        e.printStackTrace();
        return "index.xhtml";
    }

}

public String update() {
    try {
        this.emf = Persistence.createEntityManagerFactory("timesheets1");
        System.out.println("Update Getting Collection");
        Category category = (Category) getDatatable().getRowData();

        FacesContext context = FacesContext.getCurrentInstance();
        System.out.println("PHASE ID="+context.getCurrentPhaseId().toString());

        if (category != null) {
            // DESCRIPTION VALUE BELOW IS ALWAYS OLD VALUE (IE DATA IN DATABASE)
            System.out.println("updating "+category.getId()+" - " +category.getDescription());

            this.em = this.emf.createEntityManager();
            EntityTransaction tx = em.getTransaction();
            tx.begin();
            em.merge(category);
            tx.commit();
            em.close();
            emf.close();
        }else{
            System.out.println("Not found");
        }
        return "index.xhtml";
    } catch (Exception e) {
        e.printStackTrace();
        return "";
    }
}

public void setCollection(List<Category> collection) {
    this.collection = collection;
}

public List<Category> getCollection() {
    // this.emf=Persistence.createEntityManagerFactory("timesheets1");
    // System.out.println("Getting Collection");
    try {
        this.emf = Persistence.createEntityManagerFactory("timesheets1");
        this.em = this.emf.createEntityManager();
        Query query = this.em.createNamedQuery("findAll");
        this.collection = query.getResultList();
        return this.collection;
    } catch (Exception e) {
        e.printStackTrace();
        return null;
    }
}

public void setSelectedid(int id) {
    this.selectedid=id;
}

public void setSelectedcategory(Category selectedcategory) {
    this.selectedcategory = selectedcategory;
}

public HtmlDataTable getDatatable() {
    return datatable;
}

public void setDatatable(HtmlDataTable datatable) {
    this.datatable = datatable;
}
public Category getSelectedcategory() {
return selectedcategory;
 }



}

我的JPA映射实体在这里

My Mapped entity for JPA is here

package net.bssuk.timesheets.model;
import java.io.Serializable;
import javax.persistence.*;


/**
 * The persistent class for the CATEGORIES database table.
 * 
*/
@Entity
@Table(name="CATEGORIES")
@NamedQuery(name="findAll", query = "SELECT c from Category c")
public class Category implements Serializable {
private static final long serialVersionUID = 1L;

private String description;

@Id 
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;

public Category() {
}

public String getDescription() {
    return this.description;
}

public void setDescription(String description) {
    this.description = description;
}

public int getId() {
    return this.id;
}

public void setId(int id) {
    this.id = id;
}

}

确定-更新了我的代码以遵循示例.我试图将EJB合并到场景中,如下所示:

OK - Updated my code to follow example. I have tried to incorporate an EJB into the scenario as follows

package net.bssuk.timesheets.ejb;

import java.util.List;

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import net.bssuk.timesheets.model.Category;
@Stateless
public class CategoryEJB implements CategoryEJBRemote {

@PersistenceContext(unitName="timesheets1")
private EntityManager em;

@Override
public List<Category> findCategories() {
    // TODO Auto-generated method stub
    System.out.println("find categories");
    Query query = em.createNamedQuery("findAll");
    return query.getResultList();
}

@Override
public Category createCategory(Category category) {
    // TODO Auto-generated method stub
    em.persist(category);
    return category;
}

@Override
public Category udpateCategory(Category category) {
    // TODO Auto-generated method stub
    return em.merge(category);
}

@Override
public void deleteCategory(Category category) {
    // TODO Auto-generated method stub
        em.remove(em.merge(category));
}

}

我的EJB在下面

package net.bssuk.timesheets.ejb;

import java.util.List;

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import net.bssuk.timesheets.model.Category;
@Stateless
public class CategoryEJB implements CategoryEJBRemote {

@PersistenceContext(unitName="timesheets1")
private EntityManager em;

@Override
public List<Category> findCategories() {
    // TODO Auto-generated method stub
    System.out.println("find categories");
    Query query = em.createNamedQuery("findAll");
    return query.getResultList();
}

@Override
public Category createCategory(Category category) {
    // TODO Auto-generated method stub
    em.persist(category);
    return category;
}

@Override
public Category udpateCategory(Category category) {
    // TODO Auto-generated method stub
    return em.merge(category);
}

@Override
public void deleteCategory(Category category) {
    // TODO Auto-generated method stub
        em.remove(em.merge(category));
}

}

任何人都可以建议这种外观是否还可以吗?还是我完全失去了它的情节!

Can anyone suggest if this sort of looks ok? Or have I completely lost the plot with it!

推荐答案

看,

<h:dataTable var="row"  border="0" value="#{beanCategory.collection}" binding="#{beanCategory.datatable}">

public List<Category> getCollection() {
    // this.emf=Persistence.createEntityManagerFactory("timesheets1");
    // System.out.println("Getting Collection");
    try {
        this.emf = Persistence.createEntityManagerFactory("timesheets1");
        this.em = this.emf.createEntityManager();
        Query query = this.em.createNamedQuery("findAll");
        this.collection = query.getResultList();
        return this.collection;
    } catch (Exception e) {
        e.printStackTrace();
        return null;
    }
}

您正在将列表加载到getter方法中.这是一个非常糟糕的主意.吸气剂应仅是bean属性的访问点,而不是做一些商业工作.在bean的生命周期中,可以多次调用一个getter方法.该数据库将在每次调用时命中,并且JSF在表单提交期间更新的本地collection属性将在以后再次被覆盖.这是没有道理的.

You're loading the list inside a getter method. This is a very bad idea. A getter should solely be an access point to the bean property, not to do some business job. A getter can be called multiple times during bean's life. The DB will be hit on every call and the local collection property which was been updated by JSF during form submit will be overwritten again at a later point. This makes no sense.

使用(post)构造方法或action(listener)方法进行业务工作.绝对不是吸气剂.这是一个最小的启动示例,它对代码进行了一些改进:

Do the business job in the (post)constructor method or action(listener) methods. Definitely not in a getter. Here's a minimum kickoff example with some code improvements:

<h:dataTable value="#{bean.categories}" var="category">
    <h:column>
        <h:inputText value="#{category.description}" />
    </h:column>
    <h:column>
        <h:outputText value="#{category.id}" />
    </h:column>
    <h:column>
        <h:commandButton value="Delete" action="#{bean.delete(category)}" />
        <h:commandButton value="Save" action="#{bean.update(category)}" />
    </h:column>
</h:dataTable>
<h:inputText value="#{bean.newCategory.description}" />
<h:commandButton value="Add" action="#{bean.add}" />

(请注意,自EL 2.2(Servlet 3.0的一部分)以来,EL中支持传递参数,Glassfish 3是Servlet 3.0容器,因此,当正确声明web.xml符合Servlet 3.0规范时,它一定会支持它)

(note that passing arguments in EL is supported since EL 2.2 (part of Servlet 3.0), Glassfish 3 is a Servlet 3.0 container, so it should definitely support it when web.xml is properly declared conform Servlet 3.0 spec)

使用

@ManagedBean
@ViewScoped // Definitely don't use session scoped. I'm not sure about CDI approach, so here's JSF example.
public class Bean {

    private List<Category> categories;
    private Category newCategory;

    @EJB
    private CategoryService categoryService;

    @PostConstruct
    public void init() {
        categories = categoryService.list();
        newCategory = new Category();
    }

    public void add() {
        categoryService.add(newCategory);
        init();
    }

    public void delete(Category category) {
        categoryService.delete(category);
        init();
    }

    public void update(Category category) {
        categoryService.update(category);
        init();
    }

    public List<Category> getCategories() {
        return categories;
    }

    public Category getNewCategory() {
        return newCategory;
    }

}

应该的.另请参阅:

  • Why JSF calls getters multiple times
  • Help understanding JSF's multiple calls to managed bean
  • <h:dataTable value=#{myBean.xxx}>: getXxx() get called so many times, why?

这篇关于在h:dataTable中更新后,更改未反映在JPA实体中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆