对 tableview 单元格的编辑丢失

Edits to tableview cell are lost

我有一个简单的 JavaFX TableView,它由 JPA 数据库查询填充。我将一列设置为可编辑并且有效。但是,在单元格中进行更改后,只要我对 TableView 进行排序甚至导航,它就会消失。另外,您将如何将这些编辑保存回数据库?

这是 FXML 文件及其控制器:

<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import java.net.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.control.cell.*?>
<?import javafx.scene.layout.*?>

<AnchorPane id="AnchorPane" prefHeight="600.0" prefWidth="800.0" styleClass="mainFxmlClass" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.IXS.synergyixs.ingestor.ViewUsersController">
    <stylesheets>
        <URL value="@/styles/IssueTrackingLite.css" />
    </stylesheets>
    <children>
        <TableView fx:id="loginsTable" editable="true" prefHeight="593.0" prefWidth="794.0">
            <columns>
                <TableColumn fx:id="idCol" editable="false" text="Id">
                </TableColumn>
                <TableColumn fx:id="loginCol" text="Login">
                </TableColumn>
                <TableColumn fx:id="partyCol" editable="false" text="Party ID">
                </TableColumn>
                <TableColumn fx:id="creatorCol" editable="false" text="Creator ID">
                </TableColumn>
                <TableColumn fx:id="modifierCol" editable="false" text="Modifier ID">
                </TableColumn>
            </columns>
        </TableView>
    </children>
</AnchorPane>

控制器:

package com.IXS.synergyixs.ingestor;

import com.IXS.synergyixs.ingestor.data.Usr;
import java.net.URL;
import java.util.List;
import java.util.ResourceBundle;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.scene.layout.Pane;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

/**
 * FXML Controller class
 *
 * @author Owner
 */
public class ViewUsersController implements Initializable {

    public EntityManagerFactory emf = Persistence.createEntityManagerFactory("com.mycompany_SynergyIXS-Ingestor_jar_1.0-SNAPSHOTPU");
    public EntityManager em = emf.createEntityManager();

    public ObservableList<Usr> tableData;
    public Usr currentUsr;
    /**
     * Initializes the controller class.
     */
    @FXML
    private Pane rootPane;
    @FXML
    private TableView<Usr> loginsTable;

    @FXML
    private TableColumn<Usr, Number> idCol;

    @FXML
    private TableColumn<Usr, String> loginCol;

    @FXML
    private TableColumn<Usr, Number> partyCol;

    @FXML
    private TableColumn<Usr, Number> creatorCol;

    @FXML
    private TableColumn<Usr, Integer> modifierCol;

    @Override
    public void initialize(URL location, ResourceBundle resources) {

        /* to verify query is returning data
        for (Usr u : userList) {
            System.out.println(u.getId() + " " + u.getLogin());
        }
         */
        idCol.setCellValueFactory(new PropertyValueFactory<>("id"));

        loginCol.setCellValueFactory(new PropertyValueFactory<>("login"));
        loginCol.setCellFactory(TextFieldTableCell.forTableColumn‌());

        partyCol.setCellValueFactory(new PropertyValueFactory<>("partyId"));

        creatorCol.setCellValueFactory(new PropertyValueFactory<>("creatorId"));

        modifierCol.setCellValueFactory(new PropertyValueFactory<>("modifierId"));
        updateUserList();
        loginsTable.setItems(tableData);
    }

    public void updateUserList() {
        List<Usr> userList = em.createNamedQuery("Usr.findAll").getResultList();
        if (tableData == null) {
            tableData = FXCollections.observableArrayList(userList);
        } else {
            tableData.clear();
            tableData.addAll(userList);
        }
    }
    /*
    public void saveUser()
    {
        em.getTransaction().begin();
        em.persist(currentUsr);
        em.getTransaction().commit();
        updateUserList();
    }
     */
}​

用户 class:

package com.IXS.synergyixs.ingestor.data;

import java.io.Serializable;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Date;
import java.util.List;
import javax.persistence.Basic;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;

/**
 *
 * @author Owner
 */
@Entity
@Table(name = "USR", catalog = "", schema = "ADMIN")
@XmlRootElement
@NamedQueries({
    @NamedQuery(name = "Usr.findAll", query = "SELECT u FROM Usr u")
    , @NamedQuery(name = "Usr.findById", query = "SELECT u FROM Usr u WHERE u.id = :id")
    , @NamedQuery(name = "Usr.findAllLogin", query = "SELECT u.login FROM Usr u")
    , @NamedQuery(name = "Usr.findByLogin", query = "SELECT u FROM Usr u WHERE u.login = :login")
    , @NamedQuery(name = "Usr.findByPwd", query = "SELECT u FROM Usr u WHERE u.pwd = :pwd")
    , @NamedQuery(name = "Usr.findByPartyId", query = "SELECT u FROM Usr u WHERE u.partyId = :partyId")
    , @NamedQuery(name = "Usr.findByCreatorId", query = "SELECT u FROM Usr u WHERE u.creatorId = :creatorId")
    , @NamedQuery(name = "Usr.findByCreationDttm", query = "SELECT u FROM Usr u WHERE u.creationDttm = :creationDttm")
    , @NamedQuery(name = "Usr.findByModifierId", query = "SELECT u FROM Usr u WHERE u.modifierId = :modifierId")
    , @NamedQuery(name = "Usr.findByModificationDttm", query = "SELECT u FROM Usr u WHERE u.modificationDttm = :modificationDttm")})
public class Usr implements Serializable {

    private static final long serialVersionUID = 1L;
    // @Max(value=?)  @Min(value=?)//if you know range of your decimal fields consider using these annotations to enforce field validation
    @Id
    @Basic(optional = false)
    @Column(name = "ID")
    private BigDecimal id;
    @Basic(optional = false)
    @Column(name = "LOGIN")
    private String login;
    @Basic(optional = false)
    @Column(name = "PWD")
    private String pwd;
    @Column(name = "PARTY_ID")
    private BigInteger partyId;
    @Basic(optional = false)
    @Column(name = "CREATOR_ID")
    private BigInteger creatorId;
    @Basic(optional = false)
    @Column(name = "CREATION_DTTM")
    @Temporal(TemporalType.TIMESTAMP)
    private Date creationDttm;
    @Basic(optional = false)
    @Column(name = "MODIFIER_ID")
    private BigInteger modifierId;
    @Basic(optional = false)
    @Column(name = "MODIFICATION_DTTM")
    @Temporal(TemporalType.TIMESTAMP)
    private Date modificationDttm;
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "usr")
    private List<UsrAppRole> usrAppRoleList;

    public Usr() {
    }

    public Usr(BigDecimal id) {
        this.id = id;
    }

    public Usr(BigDecimal id, String login, String pwd, BigInteger creatorId, Date creationDttm, BigInteger modifierId, Date modificationDttm) {
        this.id = id;
        this.login = login;
        this.pwd = pwd;
        this.creatorId = creatorId;
        this.creationDttm = creationDttm;
        this.modifierId = modifierId;
        this.modificationDttm = modificationDttm;
    }

    public BigDecimal getId() {
        return id;
    }

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

    public String getLogin() {
        return login;
    }

    public void setLogin(String login) {
        this.login = login;
    }

    public String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

    public BigInteger getPartyId() {
        return partyId;
    }

    public void setPartyId(BigInteger partyId) {
        this.partyId = partyId;
    }

    public BigInteger getCreatorId() {
        return creatorId;
    }

    public void setCreatorId(BigInteger creatorId) {
        this.creatorId = creatorId;
    }

    public Date getCreationDttm() {
        return creationDttm;
    }

    public void setCreationDttm(Date creationDttm) {
        this.creationDttm = creationDttm;
    }

    public BigInteger getModifierId() {
        return modifierId;
    }

    public void setModifierId(BigInteger modifierId) {
        this.modifierId = modifierId;
    }

    public Date getModificationDttm() {
        return modificationDttm;
    }

    public void setModificationDttm(Date modificationDttm) {
        this.modificationDttm = modificationDttm;
    }

    @XmlTransient
    public List<UsrAppRole> getUsrAppRoleList() {
        return usrAppRoleList;
    }

    public void setUsrAppRoleList(List<UsrAppRole> usrAppRoleList) {
        this.usrAppRoleList = usrAppRoleList;
    }

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (id != null ? id.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof Usr)) {
            return false;
        }
        Usr other = (Usr) 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 "com.mycompany.synergyixs.ingestor.Usr[ id=" + id + " ]";
    }

}

默认的 onEditCommit 处理程序假定 table 的模型使用 JavaFX properties pattern (see TableView documentation,标题为 "Editing" 的部分)。由于您的 Usr class 本质上是一个普通的 JavaBean,没有 属性 访问器方法,因此默认处理程序缩减为 no-op。

您需要重构 Usr class 以便它使用 JavaFX 属性(有关在 JPA 实体中使用 JavaFX 属性的讨论,请参阅 Using javafx.beans properties in model classes),或者设置一个 onEditCommit 列上的处理程序:

loginCol.setOnEditCommit(e -> {
    Usr usr = e.getRowValue();
    usr.setLogin(e.getNewValue());
});

要将值存储在数据库中,请使用 merge(...):

loginCol.setOnEditCommit(e -> {
    Usr usr = e.getRowValue();
    usr.setLogin(e.getNewValue());
    // merge change to database:
    Usr mergedUsr = em.merge(usr);
    // ensure table has same reference as ORM cache:
    loginsTable.set(e.getTablePosition().getRow(), mergedUsr);
});