Как создавать `вложенные` объекты в программном слое работы с БД без ORM? Доброго времени суток.
Возникла проблема создания вложенных объектов (класс является полем ещё одного класса) при получении коллекции из базы данных.
Например 3 класса: Сотрудники (Employee), Профессии (Profession), Отделы (Department).Упрощённый код (на Java)class Profession {
long id;
String name;
}
class Employee {
long id;
String name;
Profession profession;
}
class Department {
long id;
String name;
List employees;
}
Данные хранятся в БД MySql в 4 таблицах (согласно нормальным формам). Созданы следующим скриптом:Скрипт создания таблиц-- Профессии
CREATE TABLE Professions (
id BIGINT AUTO_INCREMENT NOT NULL,
name VARCHAR(255) CHARACTER SET utf8 NOT NULL,
PRIMARY KEY (id),
UNIQUE (name)
) ENGINE = InnoDB ROW_FORMAT = DEFAULT CHARACTER SET utf8;
-- Сотрудники
CREATE TABLE Employees (
id BIGINT AUTO_INCREMENT NOT NULL,
name VARCHAR(255) CHARACTER SET utf8 NOT NULL,
professionId BIGINT,
PRIMARY KEY (id),
CONSTRAINT EmployeeToProfession FOREIGN KEY (professionId) REFERENCES Professions (id)
ON UPDATE RESTRICT
ON DELETE RESTRICT
) ENGINE = InnoDB ROW_FORMAT = DEFAULT CHARACTER SET utf8;
-- Отделы
CREATE TABLE Departments (
id BIGINT AUTO_INCREMENT NOT NULL,
name VARCHAR(255) CHARACTER SET utf8 NOT NULL,
PRIMARY KEY (id),
UNIQUE (name)
) ENGINE = InnoDB ROW_FORMAT = DEFAULT CHARACTER SET utf8;
-- Таблица связи отдела и сотрудников
CREATE TABLE DepartmentsEmployees (
id BIGINT AUTO_INCREMENT NOT NULL,
departmentId BIGINT NOT NULL,
employeeId BIGINT NOT NULL,
PRIMARY KEY (id),
UNIQUE (employeeId),
CONSTRAINT ConstraintToDepartments FOREIGN KEY (departmentId) REFERENCES Departments (id)
ON UPDATE RESTRICT
ON DELETE RESTRICT,
CONSTRAINT ConstraintToEmployees FOREIGN KEY (employeeId) REFERENCES Employees (id)
ON UPDATE RESTRICT
ON DELETE RESTRICT
) ENGINE = InnoDB ROW_FORMAT = DEFAULT CHARACTER SET utf8;
В системе есть программное `расслоение` классов по пакетам по назначению, сервисы (services) и хранилища (storages). Код приблизительно такой:Набросок слоя сервисов и слоя работы с базой данных// services
class ProfessionService {
public List getAll() { return new ProfessionStorage().getAll(); }
}
class EmployeeService {
public List getAll() { return new EmployeeStorage().getAll(); }
}
class DepartmentService {
public List getAll() { return new DepartmentStorage().getAll(); }
}
// storages
class ProfessionStorage {
public List getAll() {
// TODO implement here
throw new UnsupportedOperationException();
}
}
class EmployeeStorage {
public List getAll() {
// TODO implement here
throw new UnsupportedOperationException();
}
}
class DepartmentStorage {
public List getAll() {
// TODO implement here
throw new UnsupportedOperationException();
}
}
И, собственно, вопрос - где и как лучше создавать связи между классами?
Пока придумал 2 варианта:
1. Передавать зависимые коллекции классов в параметрах методов и при создании объектов выбирать в цикле из списка связанный объект по id:Слой сервисов и слой работы с БД - передача коллекций в параметрах методов// services
class ProfessionService {
public List getAll() {
return new ProfessionStorage().getAll();
}
}
class EmployeeService {
public List getAll() {
ProfessionService professionService = new ProfessionService();
List professions = professionService.getAll();
return new EmployeeStorage().getAll(professions);
}
}
class DepartmentService {
public List getAll() {
EmployeeService employeeService = new EmployeeService();
List employees = employeeService.getAll();
return new DepartmentStorage().getAll(employees);
}
}
// storages
class ProfessionStorage {
public List getAll() {
// TODO implement here
throw new UnsupportedOperationException();
}
}
class EmployeeStorage {
public List getAll(List professions) {
// TODO implement here
throw new UnsupportedOperationException();
}
}
class DepartmentStorage {
public List getAll(List employees) {
// TODO implement here
throw new UnsupportedOperationException();
}
}
2. Возврат из метода Map вместо List, в котором в качестве Value указывается id связанной записи. Связь объектов осущетсвляется в методе слоя сервисов:Слой сервисов и слой работы с БД - озврат из методов хранилища Map вместо List// services
class ProfessionService {
public List getAll() { return new ProfessionStorage().getAll(); }
}
class EmployeeService {
public List getAll() {
ProfessionService professionService = new ProfessionService();
List professions = professionService.getAll();
Map employeesWithProfessionId = new EmployeeStorage().getAll();
List employees = new ArrayList<>();
for (Map.Entry entry : employeesWithProfessionId.entrySet()) {
Employee employee = entry.getKey();
Long professionId = entry.getValue();
for (Profession profession : professions) {
if (profession.id == professionId) {
employee.profession = profession;
break;
}
}
employees.add(employee);
}
return employees;
}
}
class DepartmentService {
public List getAll() {
EmployeeService employeeService = new EmployeeService();
List employees = employeeService.getAll();
Map> departmentsWithEmployeesId = new DepartmentStorage().getAll();
List departments = new ArrayList<>();
for (Map.Entry> entry : departmentsWithEmployeesId.entrySet()) {
Department department = entry.getKey();
List employeeIds = entry.getValue();
department.employees = new ArrayList<>();
for (Long employeeId : employeeIds) {
for (Employee employee : employees) {
if (employee.id == employeeId) {
department.employees.add(employee);
break;
}
}
}
departments.add(department);
}
return departments;
}
}
// storages
class ProfessionStorage {
public List getAll() {
// TODO implement here
throw new UnsupportedOperationException();
}
}
class EmployeeStorage {
public Map getAll() {
// TODO implement here
throw new UnsupportedOperationException();
}
}
class DepartmentStorage {
public Map> getAll() {
// TODO implement here
throw new UnsupportedOperationException();
}
}
Ни одно из решений особо не нравятся. Как поступить лучше?

21 Авг 2019 в 07:00
206 +1
0
Ответы
1

Для создания вложенных объектов без использования ORM, можно использовать следующий подход:

Создать отдельный метод в каждом хранилище (storage) для получения связанных данных. Например, для получения сотрудников с их профессиями и отделами.

Использовать возвращаемый тип данных Map<Long, Object>, где ключом будет идентификатор объекта, а значением сам объект. Таким образом, для каждого объекта можно легко получить связанные данные по его идентификатору.

В слое сервисов (services), после получения всех объектов из базы данных, создать связи между объектами, используя полученные данные из хранилищ.

Пример кода:

// storages
class EmployeeStorage {
public Map<Long, Employee> getAllEmployeesWithProfessionsAndDepartments() {
// TODO implement here
throw new UnsupportedOperationException();
}
}
class DepartmentStorage {
public Map<Long, Department> getAllDepartmentsWithEmployees() {
// TODO implement here
throw new UnsupportedOperationException();
}
}
// services
class EmployeeService {
public List<Employee> getAllEmployeesWithProfessionsAndDepartments() {
Map<Long, Employee> employeesWithProfessionsAndDepartments = new EmployeeStorage().getAllEmployeesWithProfessionsAndDepartments();
// Retrieve professions
ProfessionService professionService = new ProfessionService();
List<Profession> professions = professionService.getAll();
// Retrieve departments
DepartmentService departmentService = new DepartmentService();
List<Department> departments = departmentService.getAll();
// Create relationships between employees, professions and departments
List<Employee> employees = new ArrayList<>();
for (Employee employee : employeesWithProfessionsAndDepartments.values()) {
Long professionId = employee.getProfession().getId();
Long departmentId = employee.getDepartment().getId();
for (Profession profession : professions) {
if (profession.getId() == professionId) {
employee.setProfession(profession);
break;
}
}
for (Department department : departments) {
if (department.getId() == departmentId) {
employee.setDepartment(department);
break;
}
}
employees.add(employee);
}
return employees;
}
}
class DepartmentService {
public List<Department> getAll() {
Map<Long, Department> departmentsWithEmployees = new DepartmentStorage().getAllDepartmentsWithEmployees();
// Retrieve employees
EmployeeService employeeService = new EmployeeService();
List<Employee> employees = employeeService.getAllEmployeesWithProfessionsAndDepartments();
// Create relationships between departments and employees
List<Department> departments = new ArrayList<>();
for (Department department : departmentsWithEmployees.values()) {
List<Long> employeeIds = department.getEmployeeIds();
department.setEmployees(new ArrayList<>());
for (Long employeeId : employeeIds) {
for (Employee employee : employees) {
if (employee.getId() == employeeId) {
department.getEmployees().add(employee);
break;
}
}
}
departments.add(department);
}
return departments;
}
}

Таким образом, вы сможете эффективно и удобно создавать вложенные объекты без использования ORM.

20 Апр в 13:09
Не можешь разобраться в этой теме?
Обратись за помощью к экспертам
Название заказа не должно быть пустым
Введите email
Бесплатные доработки
Гарантированные бесплатные доработки
Быстрое выполнение
Быстрое выполнение от 2 часов
Проверка работы
Проверка работы на плагиат
Интересные статьи из справочника
Поможем написать учебную работу
Название заказа не должно быть пустым
Введите email
Доверьте свою работу экспертам
Разместите заказ
Наша система отправит ваш заказ на оценку 92 493 авторам
Первые отклики появятся уже в течение 10 минут
Прямой эфир