Отображение столбца в tableView - PullRequest
2 голосов
/ 11 мая 2019

Я пытаюсь отобразить и отобразить данные из таблиц, между которыми существует взаимно-однозначное отношение, используя TableView из JavaFX 8 и hibernate.

Таблица:

@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. Как это исправить?

1 Ответ

1 голос
/ 11 мая 2019

Поле 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();
...

Хотя, я советую против этого последнего, так как он немного грязный и менее эффективный (много дополнительных обращений к БД, вместо одного запроса на соединение для всех запросов на запись «один-к-одному», если есть желание); но все еще доступны.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...