Short Question: What is the best way to populate a Java FX table view with data from a database by using a record? (rather than a typical object class with getters and setters)
Full question: I have this InventoryRecord.java file that I recently created to replace a traditional Object called "Inventory" that I used to populate a tableview:
import java.util.List;
public record InventoryRecord(
String make
, String model
, String officialModel
, String upc
, List<String> category
, String type
, String description
,String vendor
, Double cost
, Double price
) {}
I would like to use this record as my framework to populate my TableView using Data from a Database (in this case its Neo4j but that's not important)
Before I had this InventoryRecord record, I was using a typical class called Inventory that looked like this (I have shortened it of course to keep the question readable, assume there are the getters/setters for each property of Inventory.)
public class Inventory {
private String make;
private String model;
private String officialModel;
private List<String> category;
private String type;
private String description;
private String vendor;
private Double cost;
private Double price;
private String upc;
//Method for actual instantiation of an Inventory Object, uses setter methods in order to perform validations for each field
public Inventory(String make, String model, String officialModel, String upc, List<String> category, String type, String description,String vendor, Double cost, Double price) {
this.setMake(make);
this.setModel(model);
this.setOfficialModel(officialModel);
this.setUpc(upc);
this.setCategory(category);
this.setType(type);
this.setDescription(description);
this.setVendor(vendor);
this.setCost(cost);
this.setPrice(price);
}
And this was how I populated the table with the query results
while (result.hasNext()) {
//result.next() serves as our iterator that increments us through the records and through the while loop
Record record = result.next();
String make = record.get("make").asString();
String model = record.get("model").asString();
String officialModel = record.get("officialModel").asString();
String upc = record.get("upc").asString();
List<String> category = record.get("categories").asList(Value::asString);
String type = record.get("type").asString();
String desc = record.get("description").asString();
String vendor = record.get("vendor").asString();
Double cost = record.get("cost").isNull() ? null : record.get("cost").asDouble();
Double price = record.get("price").isNull() ? null : record.get("price").asDouble();
//when creating the anonymous Inventory items, you can send them to the constructor with any name
inventoryTable.getItems().add(new Inventory(make, model, officialModel,upc, category, type, desc,vendor, cost, price));
}
//The property value factory must use the property names as string arguments in the constructor
makeColumn.setCellValueFactory(new PropertyValueFactory<>("make"));
modelColumn.setCellValueFactory(new PropertyValueFactory<>("model"));
officialModelColumn.setCellValueFactory(new PropertyValueFactory<>("officialModel"));
categoryColumn.setCellValueFactory(new PropertyValueFactory<>("category"));
upcColumn.setCellValueFactory(new PropertyValueFactory<>("upc"));
typeColumn.setCellValueFactory(new PropertyValueFactory<>("type"));
descriptionColumn.setCellValueFactory(new PropertyValueFactory<>("description"));
vendorColumn.setCellValueFactory(new PropertyValueFactory<>("vendor"));
costColumn.setCellValueFactory(new PropertyValueFactory<>("cost"));
priceColumn.setCellValueFactory(new PropertyValueFactory<>("price"));
inventoryTable.setItems(inventoryTable.getItems());
But how can I switch everything to a InventoryRecord rather than just the Inventory object, the .setCellValueFactory and PropertyValueFactory don't like what they see.
I tried this (with some help from Google Bard) and it seems to not give any errorsfor the strings:
makeColumn.setCellValueFactory(cellData -> new SimpleStringProperty(cellData.getValue().make()));
But for the List and Double properties/columns I tried this:
categoryColumn.setCellValueFactory(cellData -> new SimpleListProperty<List<String>>(cellData.getValue().category()));
costColumn.setCellValueFactory(cellData -> new SimpleDoubleProperty(cellData.getValue().cost()));
and I get these errors: Type mismatch: cannot convert from SimpleListProperty<List<String>> to ObservableValue<List<String>> Type mismatch: cannot convert from SimpleDoubleProperty to ObservableValue<Double>
Any help is much, much appreciated!
I tried this:
while (result.hasNext()) {
//result.next() serves as our iterator that increments us through the records and through the while loop
Record record = result.next();
String make = record.get("make").asString();
String model = record.get("model").asString();
String officialModel = record.get("officialModel").asString();
String upc = record.get("upc").asString();
List<String> category = record.get("categories").asList(Value::asString);
String type = record.get("type").asString();
String desc = record.get("description").asString();
String vendor = record.get("vendor").asString();
Double cost = record.get("cost").isNull() ? null : record.get("cost").asDouble();
Double price = record.get("price").isNull() ? null : record.get("price").asDouble();
// Create an InventoryRecord directly from the Record
InventoryRecord inventoryRecord = new InventoryRecord(make,model,officialModel,upc,category,type,desc,vendor,cost,price);
// Add the InventoryRecord to the table items
inventoryTable.getItems().add(inventoryRecord);
}
//The property value factory must use the property names as string arguments in the constructor
makeColumn.setCellValueFactory(cellData -> new SimpleStringProperty(cellData.getValue().make()));
modelColumn.setCellValueFactory(cellData -> new SimpleStringProperty(cellData.getValue().model()));
officialModelColumn.setCellValueFactory(cellData -> new SimpleStringProperty(cellData.getValue().officialModel()));
categoryColumn.setCellValueFactory(cellData -> new SimpleListProperty<List<String>>(cellData.getValue().category()));
upcColumn.setCellValueFactory(cellData -> new SimpleStringProperty(cellData.getValue().upc()));
typeColumn.setCellValueFactory(cellData -> new SimpleStringProperty(cellData.getValue().type()));
descriptionColumn.setCellValueFactory(cellData -> new SimpleStringProperty(cellData.getValue().description()));
vendorColumn.setCellValueFactory(cellData -> new SimpleStringProperty(cellData.getValue().vendor()));
costColumn.setCellValueFactory(cellData -> new SimpleDoubleProperty(cellData.getValue().cost()));
priceColumn.setCellValueFactory(cellData -> new SimpleDoubleProperty(cellData.getValue().price()));
inventoryTable.setItems(inventoryTable.getItems());
but got these errors: Type mismatch: cannot convert from SimpleListProperty<List<String>> to ObservableValue<List<String>> Type mismatch: cannot convert from SimpleDoubleProperty to ObservableValue<Double>
I expect something like this (This is how it worked with my Inventory class, the one I'm trying to replace with InventoryRecord): TableView using Inventory Class