Spring JPA ManyToMany с дополнительной таблицей сохраняется с нулевым идентификатором - PullRequest
1 голос
/ 12 апреля 2020

У меня есть следующие сущности:

@Entity
@Data
@NoArgsConstructor
public class Hero {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;
    @NotNull
    private String name;
    @OneToMany(mappedBy = "character", cascade = CascadeType.ALL, orphanRemoval = true)
    @NotEmpty
    private List<HeroSkill> heroSkills;
}

@Entity
@Data
@NoArgsConstructor
public class Skill {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;
    @Column(nullable = false)
    private String name;
}

@Entity
@Data
@NoArgsConstructor
public class HeroSkill {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;
    @ManyToOne
    @JoinColumn(name = "hero_id", referencedColumnName = "id")
    @JsonIgnore
    private Hero hero;
    @ManyToOne
    @JoinColumn(name = "skill_id", nullable = false)
    private Skill skill;
    private int ranks;
}

Мой HeroService выглядит так:

@Transactional
public void create(Hero hero) {
    heroRepository.save(hero);
}

Я использую почтальон для создания нового Героя, и это пример запроса POST:

{
    "name": "Test",
    "heroSkills": [
        {
            "skill": {
                "id": 1
            },
            "ranks": 4
        },
        {
            "skill": {
                "id": 2
            },
            "ranks": 4
        }
    ]
}

Несмотря на то, что создан герой и созданы две сущности в таблице HeroSkill, столбец heroSkill hero_id равен нулю, поэтому мои новые герои не связаны с их навыками, как должно быть.

Это работает, если я изменю свой сервис следующим образом:

@Transactional
public void save(Hero hero) {
    Hero result = heroRepository.save(hero);
    hero.getHeroSkills().stream()
            .forEach(it -> {
                it.setHero(result);
                heroSkillRepository.save(it);
            });
}

Но я думаю, что мне не нужно вручную передавать Героя каждому HeroSkill. Не в этом ли смысл добавлять CascateType.ALL (который включает CascadeType.PERSIST)?

Каков правильный подход к этому?

Заранее спасибо.

1 Ответ

1 голос
/ 12 апреля 2020

Нет ссылки на Hero (родительский) в HeroSkill (дочерний), поэтому JPA не может разрешить hero_id и установить в ноль. Используйте это heroSkill.setHero(hero), чтобы установить родителя в дочернем.

Чтобы сохранить дочернего элемента с родителем в двунаправленном отношении, вы должны задать syn c в обе стороны.

 hero.getHeroSkills().stream()
            .forEach(it -> {
                it.setHero(hero);
            });
Hero result = heroRepository.save(hero);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...