cp.
cp.

Reputation: 1271

Spring JPA difficult delete

Can someone help with the following model, implemented, but unable to delete as desired

  1. Author OneToMany with Book
  2. Book ManyToMany with Genre
  3. Genre ManyToMany with Book I can create the db and add records. I believe my cascade designation is wrong as I cannot do the following
  4. From Author, delete a book(yes odd,copyright issues:) have it deleted from Books BUT also have it removed from Genre The problem is depending on what cascade I either get FK violation on Genre delete or FK violation on Book delete. Is it a deadlock? It is a trivial pattern and must be solveable. Thank you

Upvotes: 0

Views: 120

Answers (1)

K.Nicholas
K.Nicholas

Reputation: 11561

Ultimately I think that cascade is best used to handle the case when all child relations are deleted but still I think it's a complicated annotation and not well understood by most. I think that if the Book entity owns the authors and genres relationships then the ORM has no choice but to delete the relations when a book is deleted.

When I setup a simple springboot project it seems to take case of all this.

@Entity
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Author {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id;
    @ManyToMany(mappedBy = "authors")
    @lombok.ToString.Exclude
    private Set<Book> books;
}

@Entity
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Genre {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @ManyToMany(mappedBy = "genres")
    @lombok.ToString.Exclude
    private Set<Book> books;
}

@Entity
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Book {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @ManyToMany
    private Set<Author> authors;
    @ManyToMany
    private Set<Genre> genres;
}

And an simple example:

Author author = authorRepository.save(Author.builder().build());
Genre genre = genreRepository.save(Genre.builder().build());
Book book = bookRepository.save(Book.builder().authors(Collections.singleton(author)).genres(Collections.singleton(genre)).build());
System.out.println(book);
bookRepository.delete(bookRepository.getOne(book.getId()));

And the logs seem to indicate that authors and genres are cleaned up when a book is deleted.

Hibernate: insert into author (id) values (null)
Hibernate: insert into genre (id) values (null)
Hibernate: insert into book (id) values (null)
Hibernate: insert into book_authors (books_id, authors_id) values (?, ?)
Hibernate: insert into book_genres (books_id, genres_id) values (?, ?)
Book(id=1, authors=[Author(id=1)], genres=[Genre(id=1)])
Hibernate: select book0_.id as id1_1_0_ from book book0_ where book0_.id=?
Hibernate: delete from book_authors where books_id=?
Hibernate: delete from book_genres where books_id=?
Hibernate: delete from book where id=?

I think this is doing what your questioned is about.

Upvotes: 1

Related Questions