How to create a CRUD JavaFX tableview with MySQL and Hibernate

A JavaFX tableview allows to present the data in a tabular layout. The sorting feature comes default with a tableview, which sorts the data with any column in ascending or descending order.

We can also fetch data from the database and fill the tableview dynamically. In addition to this, In this chapter we will actually do CRUD operations with the tableview which will reflect the changes in the database. We are using MySQL database with Hibernate ORM in this example.

Our project structure looks like below:

crud tableview project structure

Create an JavaFX application called crudtableview and include following libraries:

1. Hibernate 4.3.x(JPA2.1)
2. Persistence (JPA 2.1)
3. mysql-connector-java-5.1.41-bin.jar

First create a database called crudtableview and a table named User.

CREATE TABLE `user` (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `FirstName` varchar(512) NOT NULL,
  `LastName` varchar(512) NOT NULL,
  `Email` varchar(512) NOT NULL,
  PRIMARY KEY (`ID`)
);

We need a hibernate configuration file to connect MySQL database. Let’s create a file called hibernate.cfg.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
  <session-factory>
    <!-- Database connection settings -->
    <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="connection.url">jdbc:mysql://localhost:3306/crudtableview</property>
    <property name="connection.username">root</property>
    <property name="connection.password">root</property>
    <!-- JDBC connection pool (use the built-in) -->
    <property name="connection.pool_size">1</property>
    <!-- SQL dialect -->
    <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
    <!-- Enable Hibernate's automatic session context management -->
    <property name="current_session_context_class">thread</property>
    <!-- Disable the second-level cache  -->
    <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
    <!-- Echo all executed SQL to stdout -->
    <property name="show_sql">true</property>
    <property name="format_sql">true</property>
    <property name="hbm2ddl.auto">update</property>
    <mapping class="beans.User"/>
    <!-- <mapping resource="bean/User.hbm.xml" /> -->
  </session-factory>
</hibernate-configuration>

Now create a User class inside the beans folder.

package beans;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;


@Entity
//@Table( name = "Users" )
public class User{
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name = "ID")
	private int id;
	
	@Column(name = "FirstName")
	private String firstName;
	
	@Column(name = "LastName")
	private String lastName;
	
	@Column(name = "Email")
	private String email;

	
	public User() {
		// TODO Auto-generated constructor stub
	}
	
	public User(int id, String firstName, String lastName, String email, String date, String mobile) {
		super();
		this.id = id;
		this.firstName = firstName;
		this.lastName = lastName;
		this.email = email;
	}

        public User(String firstName, String lastName, String email) {
                    this.firstName = firstName;
                    this.lastName = lastName;
                    this.email = email;
        }
	
	public int getId() {
		return id;
	}

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

	public String getFirstName() {
		return firstName;
	}

	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}

	public String getLastName() {
		return lastName;
	}

	public void setLastName(String lastName) {
		this.lastName = lastName;
	}
	
	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}
	
}

Now create a main crudtableview application


package crudtableview;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

import beans.User;
import com.sun.prism.impl.Disposer.Record;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import java.util.List;
import java.util.Optional;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.CellEditEvent;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.util.Callback;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;

public class crudtableview extends Application {

    private TextField firstName, lastName, email;
    private Stage primaryStage;
    private final Configuration cfg = new Configuration().configure("hibernate.cfg.xml");
//    private final SessionFactory sf = cfg.buildSessionFactory();
    private final StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(cfg.getProperties()).build();
    private final SessionFactory sf = cfg.configure().buildSessionFactory(serviceRegistry);

    @Override
    public void start(Stage stage) {
        primaryStage = stage;
        startApp();
    }

    private void startApp() {
        Session session1 = sf.openSession();
        List<User> users = session1.createCriteria(User.class).list();
        session1.close();

        TableView<User> table = new TableView<>();
        ObservableList<User> data = FXCollections.observableArrayList(users);

        table.setEditable(true);

        TableColumn firstNameCol = new TableColumn("First Name");
        firstNameCol.setMinWidth(200);
        firstNameCol.setCellValueFactory(new PropertyValueFactory<User, String>("firstName"));
        firstNameCol.setCellFactory(TextFieldTableCell.forTableColumn());
        firstNameCol.setOnEditCommit(new EventHandler<CellEditEvent<User, String>>() {
            @Override
            public void handle(CellEditEvent<User, String> t) {
                int id = t.getTableView().getItems().get(t.getTablePosition().getRow()).getId();
                Session session = sf.openSession();
                session.beginTransaction();
                User user = (User) session.get(User.class, id);
                user.setFirstName(t.getNewValue());
                session.update(user);
                session.getTransaction().commit();
                session.close();
            }
        }
        );

        TableColumn lastNameCol = new TableColumn("Last Name");
        lastNameCol.setMinWidth(200);
        lastNameCol.setCellValueFactory(new PropertyValueFactory<User, String>("lastName"));
        lastNameCol.setCellFactory(TextFieldTableCell.forTableColumn());
        lastNameCol.setOnEditCommit(new EventHandler<CellEditEvent<User, String>>() {
            @Override
            public void handle(CellEditEvent<User, String> t) {

                int id = t.getTableView().getItems().get(t.getTablePosition().getRow()).getId();
                Session session = sf.openSession();
                session.beginTransaction();
                User user = (User) session.get(User.class, id);
                user.setLastName(t.getNewValue());
                session.update(user);
                session.getTransaction().commit();
                session.close();

            }
        }
        );

        TableColumn emailCol = new TableColumn("Email");
        emailCol.setMinWidth(200);
        emailCol.setCellValueFactory(new PropertyValueFactory<User, String>("email"));
        emailCol.setCellFactory(TextFieldTableCell.forTableColumn());
        emailCol.setOnEditCommit(new EventHandler<CellEditEvent<User, String>>() {
            @Override
            public void handle(CellEditEvent<User, String> t) {

                int id = t.getTableView().getItems().get(t.getTablePosition().getRow()).getId();
                Session session = sf.openSession();
                session.beginTransaction();
                User user = (User) session.get(User.class, id);
                user.setEmail(t.getNewValue());
                session.update(user);
                session.getTransaction().commit();
                session.close();
            }
        }
        );

        TableColumn deleteCol = new TableColumn<>("Action");
        deleteCol.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Record, Boolean>, ObservableValue<Boolean>>() {
            @Override
            public ObservableValue<Boolean> call(TableColumn.CellDataFeatures<Record, Boolean> p) {
                return new SimpleBooleanProperty(p.getValue() != null);
            }
        });
        deleteCol.setCellFactory(new Callback<TableColumn<Record, Boolean>, TableCell<Record, Boolean>>() {
            @Override
            public TableCell<Record, Boolean> call(TableColumn<Record, Boolean> p) {
                return new ActionButton();
            }
        });

        table.setItems(data);
        table.getColumns().addAll(firstNameCol, lastNameCol, emailCol, deleteCol);

        firstName = new TextField();
        firstName.setPromptText("First Name");
        firstName.setMinWidth(firstNameCol.getPrefWidth());
        lastName = new TextField();
        lastName.setMinWidth(lastNameCol.getPrefWidth());
        lastName.setPromptText("Last Name");
        email = new TextField();
        email.setMinWidth(emailCol.getPrefWidth());
        email.setPromptText("Email");

        final Button addButton = new Button("Add");
        addButton.setOnAction((ActionEvent e) -> {
            User user = new User();
            user.setFirstName(firstName.getText());
            user.setLastName(lastName.getText());
            user.setEmail(email.getText());
            Session session = sf.openSession();
            session.beginTransaction();
            session.save(user);
            session.getTransaction().commit();
            session.close();
            startApp();
        });

        HBox hb = new HBox();
        hb.getChildren().addAll(firstName, lastName, email, addButton);
        hb.setSpacing(3);

        VBox vbox = new VBox();
        vbox.setSpacing(5);
        vbox.setPadding(new Insets(10, 10, 10, 10));
        vbox.getChildren().addAll(table, hb);

        StackPane root = new StackPane();
        root.getChildren().addAll(vbox);

        Scene scene = new Scene(root);

        primaryStage.setTitle("Table View Sample");

        primaryStage.setScene(scene);
        primaryStage.show();
        primaryStage.setOnCloseRequest(e -> {
            Platform.exit();
            System.exit(0);
        });
    }

    public static void main(String[] args) {
        launch(args);
    }

    private class ActionButton extends TableCell<Record, Boolean> {

        final Button deleteButton = new Button("Delete");

        ActionButton() {

            deleteButton.setOnAction((ActionEvent t) -> {
                User currentUser = (User) ActionButton.this.getTableView().getItems().get(ActionButton.this.getIndex());
                Session session = sf.openSession();
                session.beginTransaction();

                Alert alert = new Alert(Alert.AlertType.INFORMATION);
                alert.setTitle("Deleting " + currentUser.getFirstName() + " " + currentUser.getLastName());
                alert.setHeaderText("Are you Sure, You want to delete " + currentUser.getFirstName() + " " + currentUser.getLastName());
                alert.setContentText("This action can't be undone!");
                Optional<ButtonType> result = alert.showAndWait();

                if (result.get() == ButtonType.OK) {
                    session.delete(currentUser);
                    session.getTransaction().commit();
                    session.close();
                    startApp();
                }
            });
        }

        @Override
        protected void updateItem(Boolean t, boolean empty) {
            super.updateItem(t, empty);
            if (!empty) {
                setGraphic(deleteButton);
            }
        }
    }
}

Leave a Reply

Your email address will not be published. Required fields are marked *