Я создал приложение JavaFX для данных о судах, сотрудниках и рабочих местах. Текущая версия работает, но она довольно медленная, которую мне нужно исправить. Я понимаю корень своих проблем, но не знаю, как этого избежать
У меня есть несколько сущностей
class Vessel
{
IntegerProperty id;
StringProperty name;
//and some other fields...
}
class Employee
{
IntegerProperty id;
StringProperty name;
//and some other fields...
}
class Job
{
IntegerProperty id;
StringProperty name;
IntegerProperty employee;
//and also a list of vessels assigned to it
//and many more fields...
}
Эти сущности соответствуют следующим таблицам (PostgreSQL)
CREATE TABLE vessels(id SERIAL PRIMARY KEY, "name" VARCHAR);
CREATE TABLE employees(id SERIAL PRIMARY KEY, "name" VARCHAR);
CREATE TABLE jobs(id SERIAL PRIMARY KEY, "name" VARCHAR);
CREATE TABLE jobs_vessels(id SERIAL PRIMARY KEY, job INT REFERENCES jobs(id), vessel INT REFERENCES vessels(id));
Если я имею дело с Vessel
s, Employee
s или другими простыми объектами (поля являются простыми типами), я выполняю
SELECT * FROM vessels ORDER BY "name";
, за которым следует стандартный код JDBC с Connection
, PreparedStatement
и ResultSet
.
Затем я создаю ObservableList<Vessel>
и заполняю его данными из ResultSet
.
Затем я создаю TableView
, инициализирую его TableColumn
s (которые в основном TextFieldTableCell
) и, наконец, отображаю данные.
Проблема возникает, когда я хочу отобразить \ изменить список сложных объектов (поля имеют тип "класс ...").
Первая часть будет выглядеть так же ...
Я исполняю
SELECT * FROM jobs ORDER BY "name";
и затем я конвертирую ResultSet resultSet
в ObservableList<Job> jobs
.
Мне также нужно назначить суда для каждой работы, поэтому я делаю
protected Map<Job, List<int>> jobsVesselsMap;
//...
for (Job job : jobs)
{
//1. get list of vessels (ids) assigned to the job via "SELECT * FROM jobs_vessels WHERE job = ?"
//2. convert ResultSet to List<int>
//3. store List<int> to "jobsVesselsMap".
}
Поскольку мне нужно изменить назначенные суда и сотрудника (чтобы пользователь мог выбрать их с помощью соответствующих ComboBox
s), мне нужно еще 2 списка: список судов и список сотрудников.
Я исполняю
SELECT * FROM vessels ORDER BY "name";
и преобразовать ResultSet
в ObservableList<Vessel>
.
Затем я выполняю
SELECT * FROM employees ORDER BY "name";
и преобразовать ResultSet
в ObservableList<Employee>
.
Теперь идет медленная часть.
Поскольку полный объект "задание" должен содержать фактические данные о судах и сотрудниках, мне нужно поменять идентификаторы на реальные объекты.
Полное задание представлено объектом типа JobEx
class JobEx
{
IntegerProperty id;
StringProperty name;
ObjectProperty<Employee> employee;
ListProperty<Vessel> vessels;
//and many more fields...
}
Я конвертирую ObservableList<Job>
в ObservableList<JobEx>
, вызывая toJobEx
в цикле.
public static JobEx toJobEx(Job job,
ObservableList<Vessel> vessels,
ObservableList<Employee> employees,
List<int> jobVesselsIds)
{
JobEx jobEx = new JobEx();
jobEx.setId(job.getId());
jobEx.setName(job.getName());
//employee
Optional<Employee> employee = employees.stream().filter(e -> e.getId() == job.getEmployee()).findFirst();
if (employee.isPresent())
{
jobEx.setVessel(employee.get());
}
//vessels
ObservableList<Vessel> jobVessels = FXCollections.observableArrayList();
for (int vesselId : jobVesselsIds)
{
Optional<Vessel> vessel = vessels.stream().filter(v -> v.getId() == vesselId).findFirst();
if (vessel.isPresent())
{
jobEx.setVessel(vessel.get());
}
}
jobEx.setVessels(jobVessels);
return jobEx;
}
//...
ObservableList<JobEx> jobExs = FXCollections.observableArrayList();
for (Job job : jobs)
{
jobExs.add(toJobEx(job));
}
На этом шаге у меня есть полный список работ, и я начинаю его отображать.
Я создаю TableView
, создаю TableColumns
, устанавливаю соответствующие редакторы для его ячеек (TextFieldTableCell
для StringProperty
s, ComboBoxTableCell
для ObjectProperty<Employees>
, пользовательский редактор (несколько комбинированных списков + кнопки) для ` ListProperty.
Когда я хочу сохранить данные, я выполняю этот процесс в обратном порядке: ObservableList<JobEx>
-> ObservableList<Job>
-> сохранить в нескольких таблицах.
Теперь в выпадающих списках внутри таблицы правильно отображаются выбранные значения, поскольку поля каждого экземпляра JobEx
и членов списков, которые использовались для заполнения этих выпадающих списков, указывают на одну и ту же память и одинаковые адреса, что означает, что выпадающие списки автоматически выбирают значения, что и является Я хочу достичь.
Положительной стороной является то, что я могу использовать привязки JavaFX и легко выбирать \ манипулировать значениями через списки, комбинированные списки и аналогичные элементы управления пользовательским интерфейсом. Я не знаю, как добиться того же, сохраняя идентификаторы (без подхода «идентификатор объекта, массив идентификаторов списков объектов»).
Недостатком является то, что это преобразование Job
в JobEx
занимает много времени (иногда слишком много), и в реальном приложении гораздо больше классов "... Ex", которые имеют объекты вместо идентификаторов, что приводит к большому количеству кода и болезненные времена загрузки.
Есть ли способ избежать этого. В идеале, я хотел бы полностью удалить эту часть "в ... Ex преобразование", потому что это медленно и чувствует себя очень неправильно.