我正在尝试使用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。如何解决?
答案 0 :(得分:1)
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();
...
尽管如此,我还是建议您不要使用最后一个,因为它有点脏且性能较差(许多额外的往返数据库操作, 如果需要,可以代替所有一对一记录查询的单个联接查询);但仍然可用。