我正在尝试使用JavaFX 8和休眠中的TableView
映射和显示表之间的数据,表之间存在一对一关系。
表格:
@Entity
@Table(name = "CLUB")
public class Club implements Serializable {
@Id
@Column(name = "CLUB_ID", nullable = false, unique = true)
private int clubId;
@Column(name = "NAME", nullable = false, length = 100)
private String name;
@Column(name = "CITY", length = 50)
private String city;
@OneToOne(fetch = FetchType.LAZY, mappedBy = "club", cascade = CascadeType.ALL)
private Trainer trainer;
// constructor, getters, setters
}
和
@Entity
@Table(name = "TRAINER")
public class Trainer implements Serializable {
@Id
@Column(name = "LICENCE_NR", nullable = false, unique = true)
private int licenceNr;
@Column(name = "NAME", nullable = false, length = 50)
private String name;
@Column(name = "SURNAME", nullable = false, length = 50)
private String surname;
@OneToOne(fetch = FetchType.LAZY)
@PrimaryKeyJoinColumn
private Club club;
// constructor, getters, setters
}
带有
ClubController
的TableView
类:public class ClubController implements Initializable {
...
@FXML
private TableView<Club> clubTableView;
@FXML
private TableColumn<Club, String> nameColumn;
@FXML
private TableColumn<Club, String> cityColumn;
@FXML
private TableColumn<Club, Integer> trainerColumn;
@Override
public void initialize(URL location, ResourceBundle resources) {
nameColumn.setCellValueFactory(new PropertyValueFactory<Club, String>("name"));
cityColumn.setCellValueFactory(new PropertyValueFactory<Club, String>("city"));
trainerColumn.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Club, Integer>, ObservableValue<Integer>>() {
@Override
public ObservableValue<Integer> call(TableColumn.CellDataFeatures<Club, Integer> param) {
return new SimpleIntegerProperty(param.getValue().getTrainer().getLicenceNr()).asObject();
}
});
clubTableView.setItems(getClub());
}
private ObservableList<Club> getClub() {
ObservableList<Club> clubList = FXCollections.observableArrayList();
Session session = HibernateUtil.config().openSession();
List<Club> cList = session.createCriteria(Club.class).list();
clubList.addAll(cList);
session.close();
return clubList;
}
...
}
前两列可以正常工作,但是在
trainerColumn
中,我有NPE。如何解决? 最佳答案
trainer
实体中的CLUB
字段是延迟加载的:
...
@OneToOne(fetch = FetchType.LAZY, mappedBy = "club", cascade = CascadeType.ALL)
private Trainer trainer;
...
...只能在打开创建实体的会话时读取。
在
ClubController
中,您打开和关闭了会话,而没有从数据库中明确加载trainer
详细信息: private ObservableList<Club> getClub() {
ObservableList<Club> clubList = FXCollections.observableArrayList();
// SESSION OPENED
Session session = HibernateUtil.config().openSession();
// CLUB ENTITIES LOADED WITH LAZY TRAINERS
List<Club> cList = session.createCriteria(Club.class).list();
clubList.addAll(cList);
//SESSION CLOSED
session.close();
return clubList;
}
因此,要么使
trainer
实体中的CLUB
字段都渴望加载:...
@OneToOne(fetch = FetchType.EAGER, mappedBy = "club", cascade = CascadeType.ALL)
private Trainer trainer;
...
或在查询数据库时显式加载
trainer
,方法很简单:...
// SESSION OPENED
Session session = HibernateUtil.config().openSession();
// CLUB ENTITIES LOADED WITH LAZY TRAINERS
List<Club> cList = session.createCriteria(Club.class).list();
// EXPLICITLY LOAD ALL TRAINERS FROM DB
cList.stream().peek(club -> club.getTrainer().getLicenceNr())
clubList.addAll(cList);
//SESSION CLOSED
session.close();
...
尽管我建议不要使用最后一个,因为它有点脏且性能较差(许多额外的往返数据库操作,
如果需要,则不是针对所有一对一记录查询的单个联接查询);但仍然可用。