Klaus
Klaus

Reputation: 2396

Spring JPA - Delete Child in One-toMany relationship

I have the following Author class:

@Entity
public class Author  implements Serializable{

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue
    private Long id;

    @OneToMany(fetch = FetchType.EAGER, cascade=CascadeType.ALL)
    @JoinTable(
        name="author_book",
        joinColumns = @JoinColumn( name="author_id"),
        inverseJoinColumns = @JoinColumn( name="book_id")
    )
    private Set<Book> books= new HashSet<Book>();

    public Author() {
        super();
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Set<Book> getBooks() {
       return books;
    }

    public void setBooks(Set<Book> books) {
        this.books = books;
    }
 }

I also have the following book entity:

@Entity
public class Book implements Serializable{

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue
    private Long id;

    public Book() {
        super();
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

}

Next, I have the following two repositories:

public interface BookRepository extends CrudRepository<Book, Long> {
}
public interface AuthorRepository extends CrudRepository<Author, Long>{
}

And finally, I have the following test case:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(Application.class)
public class AuthorRepositoryIntegrationTests {

    @Autowired
    AuthorRepository authorRepository;
    @Autowired
    BookRepository bookRepository;

    @Test
    @Transactional
    public void deleteBookFromAuthor() {
        Book book= new Book();
        Author author= new Author();
        author.getBooks().add(book);
        author=this.authorRepository.save(author);

        Iterable<Author> authors = this.authorRepository.findAll();
        author=authors.iterator().next();
        book=author.getBooks().iterator().next();
        this.bookRepository.delete(book);

        authors = this.authorRepository.findAll();
        assertEquals(authors.iterator().next().getBooks().size(),0);
    }
}

My question is that the last assertion in this test case is failing. If I add a book to an author it gets automatically added to the book repository. But if I remove a book from the repository, how do I get it removed from the authors?

Upvotes: 2

Views: 4132

Answers (1)

K.Nicholas
K.Nicholas

Reputation: 11551

REDO: Okay, my apologies, I didn't look close enough at your question. The answer though is simple enough, and this time I actually tried it. You need to remove the child from the parent in the POJO and resave the parent without the child. See commented code below:

List<Book> books = new ArrayList<Book>();

Book book = new Book();
books.add(book);

Author author = new Author();
author.setBooks(books);
authorRepository.save(author);

Author a =authorRepository.findAll().iterator().next();
Book b = a.getBooks().get(0);
bookRepository.delete(b);

// REMOVE FROM PARENT
a.getBooks().remove(0);
authorRepository.save(a);

a = authorRepository.findAll().iterator().next();
System.out.println(a);

EDIT: If you're worried about consistency, which you should be, simply delete the book from the author POJO and when you save author the cascade=CascadeType.ALL will propagate the delete the book for you. E.g.:

Author a =authorRepository.findAll().iterator().next();
a.getBooks().remove(0);
authorRepository.save(a);

// NO BOOK
a = authorRepository.findAll().iterator().next();
System.out.println(a);

Upvotes: 1

Related Questions