Как правильно сохранить связанные объекты? - PullRequest
0 голосов
/ 15 октября 2018

Допустим, у нас есть следующие три сущности модели домена: Company, Departament и Employee.

@Getter @Setter @NoArgsConstrutor
public class Employee {
    private String name;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "department_id", nullable = false, insertable = false, updatable = false)
    private Department department;

    @JoinColumn(name = "department_id", nullable = false)
    private int department_id;
}

@Getter @Setter @NoArgsConstrutor
public class Department {
    private String name;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "company_id", nullable = false, insertable = false, updatable = false)
    private Company company;

    @JoinColumn(name = "company_id", nullable = false)
    private int company_id;

    @OneToMany(mappedBy = "department")
    private List<Employee> employees;
}

@Getter @Setter @NoArgsConstrutor
private class Company {
    private String name;

    @OneToMany(mappedBy = "company")
    private List<Department> departments;
}

Для каждой сущности у нас есть Repositories, которые расширяют JpaRepositoryServices и Controllers.В каждом Service мы @Autowire соответствующем Repository, а в каждом объекте Controller мы вызываем методы из объекта Service.

Моя проблема заключается в следующем :Я не могу сохранить весь Company, потому что для Departments требуется Company ID и Employees a Deparment ID.Итак, во-первых, в моем CompanyService я сохраняю, а затем очищаю список departments, делаю saveAndFlush, который присваивает идентификатор моему company.Я назначаю полученный идентификатор каждому company_id в каждом объекте ранее сохраненного списка departments, затем присоединяю список обратно к company и выполняю еще один saveAndFlush, и я делаю это еще раз для employee list.

@RestController
public class CompanyController {
    @Autowire
    private CompanyService companyService;

    @PostMapping("/companies")
    public Company createCompany(@RequestBody Company newCompany) {
        return companyService.createCompany(newCompany);
    }
}

@Service
public class CompanyService {
    @Autowire
    private CompanyRepository companyRepository;

    public Company createCompany(Company company) {
        List<Department> departments = new ArrayList<>(company.getDepartments());
        company.getDepartments().clear();

        companyRepository.saveAndFlush(company);

        int company_id = company.getId();

        departments.forEach (department ->
            department.setCompany_id(company_id);
        );

        //here I save a copy of the previously saved departments, because I still need the employees
        company.getDepartments().addAll(departments.stream().map(department -> department.clone(department)).collect(Collectors.toList()));
        company.getDepartments().forEach(department -> department.getEmployees().clear());

        companyRepository.saveAndFlush(company);

        //here I assign each employee it's corresponding department ID
        for (int i = 0; i < company.getDepartments().size(); i++) {
            Department departmentInSavedCompany = company.getDepartments().get(i);
            Department departmentWhichStillHasEmployees = departments.get(i);

            departmentWhichStillHasEmployees.setId(departmentInSavedCompany.getId());
            departmentWhichStillHasEmployees.getEmployees().forEach(employee -> employee.setDepartment_id(departmentInSavedCompany.getId()));
        }

        company.getDepartments.clear();
        company.getDepartments.addAll(departments);

        return companyRepository.saveAndFlush(company);
    }
}

@Repository
public interface CompanyRepository extends JpaRepository<Company, Integer> {

}

Мне не нравится эта реализация, и я не нахожу ее хорошей.Какой правильный подход к этой ситуации?

1 Ответ

0 голосов
/ 16 октября 2018

При работе с JPA не работайте с идентификаторами, работайте со ссылками на объекты.

В вашем случае это означает удаление атрибутов идентификаторов, дублирующих ссылки.

Для получениясоответствующие сущности для идентификаторов используют JpaRepository.getOne.Он вернет либо сущность, если она уже находится в кеше 1-го уровня, либо прокси-сервер, просто упаковывающий идентификатор, поэтому он не попадет в базу данных.

Это позволяет вам собрать свой граф объектов и сохранить его водин проход, начинающийся с сущности, не имеющей ссылок на другие сущности.

Вы можете также рассмотреть возможность настройки каскадирования, если вы считаете, что сущности являются частью одного и того же агрегата, то есть они должны быть загружены и сохранены вместе.

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