Spring Data JPA - сохранение нового объекта с существующим вложенным дочерним элементом - PullRequest
0 голосов
/ 28 февраля 2020

У меня есть две сущности, называемые School и Level, с отношением «многие ко многим».

@Data
@Entity
public class School {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "school_generator")
    @SequenceGenerator(name="school_generator", sequenceName = "school_seq", allocationSize=1)
    @Column(name = "school_id")
    private Long id;

    @NotBlank
    private String name;

    @NotBlank
    private String city;

    @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
    @JoinTable(
            name = "school_level",
            joinColumns = @JoinColumn(name = "school_id"),
            inverseJoinColumns = @JoinColumn(name = "level_id"))
    private Set<Level> levels = new HashSet<>();

}

@Data
@Entity
public class Level implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "level_generator")
    @SequenceGenerator(name = "level_generator", sequenceName = "level_seq", allocationSize = 1)
    @Column(name = "level_id")
    private Long id;

    @NotBlank
    @Column(nullable = false, unique = true)
    private String name;

}

My SchoolController, контроллер Rest, имеет метод create, который принимает SchoolDTO (сейчас это имеет ту же структуру, что и объект).

Когда я публикую DTO, уровни вложенного дочернего списка заполняются только существующими идентификаторами уровней (так как уровни создаются ранее).

Когда я пытаюсь сохранить с помощью метода сохранения JPARepository ... Выдается исключение с этим сообщением:

"detached entity passed to persist: com.salimrahmani.adawat.domain.Level; nested exception is org.hibernate.PersistentObjectException: detached entity passed to persist: com.salimrahmani.adawat.domain.Level",
    "trace": "org.springframework.dao.InvalidDataAccessApiUsageException: detached entity passed to persist:

Проблема решается путем итерации каждого идентификатора уровня ... получить ссылки с помощью метода репозитория JPA getOne (который вызывает entityManager.getReference), а затем загружает правильную модель и затем успешно сохраняется.

@PostMapping("/{id}/grades")
public ResponseEntity<SchoolDTO> addLevelToPackage(@PathVariable Long id, @RequestBody @Valid LevelDTO levelDTO) {
        return schoolService.findById(id)
                .map(school -> {
                    Level level = levelMapper.map(levelDTO);

                    if(level.getId() != null) {
                        level = levelService.getOne(level.getId());
                        school.getLevels().add(level);
                    } // else error

                    School saved = schoolService.save(school);

                    return ResponseEntity.ok(schoolMapper.map(saved));

                }).orElseGet(() -> ResponseEntity.notFound().build());
    }

Мой вопрос: это "единственный" правильный способ публикации ассоциации в Spring Data? Или есть способ получше?

1 Ответ

0 голосов
/ 28 февраля 2020

В функции addLevelToPackage Зачем использовать map schoolService.findById(id).map.., если, как я думаю, schoolService вернет только один экземпляр объекта School с заданным идентификатором. Я думаю, что замены карты следующим будет достаточно:

...
School theSchool = schoolService.findById(id);
Level theLevel = levelService.getOne(levelDTO.getId());
theSchool.getLevels().add(theLevel);
School saved = schoolService.save(theSchool);
return ResponseEntity.ok(schoolMapper.map(saved));
...
...