Il y a 2 entités (disons Règle et Étiquette) avec une relation many-to-many utilisant une entité liée. selon la documentation de référence d'Hibernate
Règle enity :
@Entity
@Table(name = "rule")
@JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "name")
public class Rule implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NaturalId
@NotBlank
@Column(unique = true)
private String name;
@Lob
@Column(columnDefinition = "TEXT")
private String content;
@OneToMany(mappedBy = "rule", cascade = {CascadeType.PERSIST,
CascadeType.MERGE})
private List<RuleLabel> labels = new ArrayList<>();
...
Entité d'étiquetage :
@Entity
@Table(name = "label")
@JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id")
public class Label implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotBlank
private String name;
@OneToMany(mappedBy = "label", cascade = {CascadeType.PERSIST,
CascadeType.MERGE})
private List<RuleLabel> rules = new ArrayList<>();
...
Entité de liaison :
@Entity
public class RuleLabel implements Serializable {
@Id
@ManyToOne
private Rule rule;
@Id
@ManyToOne
private Label label;
...
Dépôts :
@Repository
public interface LabelRepository extends JpaRepository<Label, Long>
...
@Repository
public interface RuleRepository extends JpaRepository<Rule, Long>
...
Création d'une nouvelle entité via RuleRepository.save(Rule) fonctionne bien, mais lorsque j'essaie de mettre à jour une entité existante (la même méthode RuleRepository.save(Rule) mais l'entité à sauver contient id ), cela conduit à une boucle infinie de Hibernate : select... des requêtes :
Hibernate: select rule0_.id as id1_7_1_, rule0_.is_active as is_activ2_7_1_, rule0_.content as content3_7_1_, rule0_.is_deleted as is_delet4_7_1_, rule0_.import_section as import_s5_7_1_, rule0_.name as name6_7_1_, rule0_.rule_configuration as rule_con7_7_1_, labels1_.rule_id as rule_id1_8_3_, labels1_.label_id as label_id2_8_3_, labels1_.rule_id as rule_id1_8_0_, labels1_.label_id as label_id2_8_0_ from rule rule0_ left outer join rule_label labels1_ on rule0_.id=labels1_.rule_id where rule0_.id=?
et StackOverflowError en conséquence
java.lang.StackOverflowError: null
at com.mysql.jdbc.ServerPreparedStatement.getInstance(ServerPreparedStatement.java:332)
...
(LabelRepository agit de la même manière)
Comment le réparer ?
Mise à jour : Après avoir changé la stratégie de récupération en Lazy
@Id
@ManyToOne(fetch = FetchType.LAZY)
private Rule rule;
@Id
@ManyToOne(fetch = FetchType.LAZY)
private Label label;
le problème de la boucle infinie a disparu, mais un nouveau problème est apparu - les entités liées ne sont pas alimentées et lorsque Hibernate essaie d'insérer des valeurs dans la table de liens
Hibernate: insert into rule_label (rule_id, label_id) values (?, ?)
on obtient
org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
...
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Column 'rule_id' cannot be null