Hibernate Many-To-Many ссылка на себя. Проблема с добавлением в h2 БД. org.h2.jdbc.JdbcSQLIntegrityConstraintViolationException

У меня есть Entity:

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name = "planets")
public class Planet extends BaseEntity {

    @ManyToMany(cascade={CascadeType.ALL})
    @JoinTable(name="related_planets",
            joinColumns={@JoinColumn(name="closing_id")},
            inverseJoinColumns={@JoinColumn(name="opening_id")})
    private Set<Planet> openingPlanets = new HashSet<>();

    @ManyToMany(cascade={CascadeType.ALL})
    @JoinTable(name="related_planets",
            joinColumns={@JoinColumn(name="opening_id")},
            inverseJoinColumns={@JoinColumn(name="closing_id")})
    private Set<Planet> closingPlanets = new HashSet<>();
}

Код популяции БД:

Planet moon = new Planet();
Planet earth = new Planet();
Planet mars = new Planet();
mars.getOpeningPlanets().add(moon);
mars.getClosingPlanets().add(earth);

planetSDJPAService.save(mars);
planetSDJPAService.save(earth);
planetSDJPAService.save(moon);

В БД, в таблицу related_planets попадают правильные значения, но при этом

moon.getClosingPlanets()

по-прежнему возвращает пустое множество. Покопавшись в StackOverflow я понял, что это не происходит автоматически, а надо добавлять самому. Я добавил следующие методы для добавления в множества:

public void putOpeningPlanet(Planet openingPlanet) {
    openingPlanet.closingPlanets.add(this);
    this.openingPlanets.add(openingPlanet);
}

public void putClosingPlanet(Planet closingPlanet) {
    closingPlanet.openingPlanets.add(this);
    this.closingPlanets.add(closingPlanet);
}

Код для популяции стал следующим:

Planet moon = new Planet();
Planet earth = new Planet();
Planet mars = new Planet();
mars.putOpeningPlanet(moon);
mars.putClosingPlanet(earth);

planetSDJPAService.save(mars);
planetSDJPAService.save(earth);
planetSDJPAService.save(moon);

Но теперь я получаю ошибку из-за вставки не уникальных значений в related_planets:

Caused by: org.h2.jdbc.JdbcSQLIntegrityConstraintViolationException: Unique index or primary key violation: "PUBLIC.PRIMARY_KEY_1 ON PUBLIC.RELATED_PLANETS(OPENING_ID, CLOSING_ID) VALUES 1"; SQL statement: insert into related_planets (closing_id, opening_id) values (?, ?) [23505-200]

Как можно решить эту проблему?


Ответы (2 шт):

Автор решения: azlov

Вы пытаетесь вставить одну запись дважды. Обратите внимание на SQL, который получается:

mars.putOpeningPlanet(moon); // допустим moon ID = 1, mars ID = 3

public void putOpeningPlanet(Planet openingPlanet) {
    openingPlanet.closingPlanets.add(this); //INSERT INTO related_planets(opening_id, closing_id) VALUES (1, 3);
    this.openingPlanets.add(openingPlanet); //INSERT INTO related_planets(opening_id, closing_id) VALUES (1, 3);
}
→ Ссылка
Автор решения: Arman Kostandov

Проблема исчезла после замены аннотаций в Entity. Код ниже:

@ManyToMany(cascade={CascadeType.ALL})
@JoinTable(name="related_planets",
        joinColumns={@JoinColumn(name="closing_id")},
        inverseJoinColumns={@JoinColumn(name="opening_id")})
private Set<Planet> openingPlanets = new HashSet<>();

@ManyToMany(cascade = {CascadeType.ALL}, mappedBy = "openingPlanets")
private Set<Planet> closingPlanets = new HashSet<>();
→ Ссылка