¿Por qué obtengo una java.sql.SQLIntegrityConstraintViolationException en una relación many-to-many de Hibernate (restricción de clave externa)?
Tengo una tabla llamada “tbl_books” que tiene una relación muchos a muchos con “tbl_author”. Quiero guardar un libro y sus autores. Puedo guardar el libro si no incluyo una lista de autores, pero ¿cómo debo guardar los autores al libro? ¿Necesito crear la tabla “tbl_book_authors” para lograr esto?
{
“title”: “un nuevo libro”,
“publisher”: {
“id”: 7
},
“authors”: [
{
“id”: 3
}
]
}
Imagen:
Log:
Book.java
…
@NoArgsConstructor
@Entity(name=”Book”)
@Table(name=”tblBook”)
public class Book {
@Id
@Column(name = "id", unique = true, nullable = false)
private int id;
private String title;
@ManyToOne(fetch = FetchType.EAGER, optional = false)
@JoinColumn(name = "pub_id", nullable = false)
private Publisher publisher;
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "tblBookAuthors",
joinColumns = { @JoinColumn(name = "bookId") },
inverseJoinColumns = { @JoinColumn(name = "authorId") })
private Set<author> authors = new HashSet<>();
...
}
author.java
…
@NoArgsConstructor
@Entity(name=”Author”)
@Table(name=”tblAuthor”)
public class Author {
@Id
@Column(name = "id")
private int id;
@Column(name = "name")
private String name;
@JsonBackReference
@ManyToMany(mappedBy = "authors")
Set<book> books;
...
}
log
Book{id=0, title=’un nuevo libro’, publisher=Publisher{id=7, name=’null’, address=’null’, phone=’null’, books=null}, authors=[Author{id=3, name=’null’, books=null}]}
Hibernate: select publisher_.id, publisher_.address as address2_4_, publisher_.name as name3_4_, publisher_.phone as phone4_4_ from tbl_publisher publisher_ where publisher_.id=?
Hibernate: insert into tbl_book (pub_id, title, id) values (?, ?, ?)
Hibernate: insert into tbl_book_authors (book_id, author_id) values (?, ?)
2021-11-27 18:49:06.643 WARN 8704 — [nio-8080-exec-7] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 1452, SQLState: 23000
2021-11-27 18:49:06.643 ERROR 8704 — [nio-8080-exec-7] o.h.engine.jdbc.spi.SqlExceptionHelper : No se puede agregar o actualizar una fila secundaria: falla una restricción de clave externa (library
.tbl_book_autors
, CONSTRAINT fk_tbl_book_authors_tbl_book1
FOREIGN KEY (book_id
) REFERENCES tbl_book
(id
) ON DELETE CASCADE ON UPDATE CASCADE)
2021-11-27 18:49:06.644 INFO 8704 — [nio-8080-exec-7] o.h.e.j.b.internal.AbstractBatchImpl : HHH000010: En la liberación del conjunto todavía contenía declaraciones JDBC
2021-11-27 18:49:06.663 ERROR 8704 — [nio-8080-exec-7] o.a.c.c.C.[.[.[/].[dispatcherServlet] : El servlet.service() para el servlet [dispatcherServlet] en el contexto con ruta [] lanzó una excepción [La solicitud ha fallado; la excepción anidada es org.springframework.dao.DataIntegrityViolationException: no se pudo ejecutar la declaración; SQL [n/a]; restricción [null]; excepción anidada es org.hibernate.exception.ConstraintViolationException: no se pudo ejecutar la declaración] con la causa raíz
java.sql.SQLIntegrityConstraintViolationException: No se puede agregar o actualizar una fila secundaria: falla una restricción de clave externa (library
.tbl_book_autors
, CONSTRAINT fk_tbl_book_authors_tbl_book1
FOREIGN KEY (book_id
) REFERENCES tbl_book
(id
) ON DELETE CASCADE ON UPDATE CASCADE)
davy.ai
Para guardar un libro con sus autores, puedes incluir la lista de autores en el objeto
Book
y luego guardar el objetoBook
usando los métodosEntityManager
oCrudRepository
:En el ejemplo de JSON proporcionado, puedes ver que los IDs del libro y el autor ya están incluidos, por lo que puedes usar
entityManager.getReference()
para buscar los objetos correspondientes y agregarlos al objetoBook
.Con respecto a la tabla
tbl_book_authors
, la anotación@ManyToMany
con@JoinTable
ya crea esa tabla por ti, por lo que no necesitas crearla manualmente. El error en el registro parece estar relacionado con una restricción de clave externa, así que asegúrate de que las tablastbl_publisher
ytbl_author
tengan los datos necesarios y de que los IDs coincidan con los proporcionados en el JSON.