Rubenex
Rubenex

Reputation: 479

how to avoid inserting duplicates into DB using jpa in a many to many bidirectional relationship

I have a many to many bidirectional relationship in hibernate with entities Book and Author, an Author can write many books and a book can have many authors. the problem appears when trying to save a new book with an author that is already in the database. hibernate will create a new record in the database with the same author with a new id, how can I reference the new book to an existing author in the database instead of creating a new one?

my classes look like this.

@Entity
 @JsonIdentityInfo(
    generator = ObjectIdGenerators.PropertyGenerator.class,
    property = "id")
public class Author {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "author_id")
private Long id;

@Column(name = "name")
private String name;

@ManyToMany(cascade = CascadeType.ALL, mappedBy = "authors")
private Set<Book> books = new HashSet<>();

book class

@Entity
@JsonIdentityInfo(
    generator = ObjectIdGenerators.PropertyGenerator.class,
    property = "id")
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "book_id")
private Long id;

@Column(name = "name")
private String name;

@Column(name = "abstract")
private String bookAbstract;


@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(
        name = "book_author",
        joinColumns = {@JoinColumn(name = "book_id")},
        inverseJoinColumns = {@JoinColumn(name = "author_id")}
)
private Set<Author> authors = new HashSet<>();

I send an JSON object to the rest controller and then save the book

{
"name" : "Name of the Book",
"bookAbstract" : "an abstract",
"authors" : [
{"name":"Author1"},
{"name":"Author2"},
{"name":"Author3"}]}

I convert the JSON to a java object and the a save it using save() from JPArepository, assuming that Author1 is already in the database, the code below will create a new record of Author1,

Book book = objectMapper.readerFor(Book.class).readValue(input);
bookRepository.save(book);

Upvotes: 0

Views: 4215

Answers (1)

Maciej Kowalski
Maciej Kowalski

Reputation: 26572

Well the the way i would prevent duplicates in your case would be to:

1) Try to get the records of each of the Authors while. Assuming that you could inject the repository into the mapper then:

Book book = assembleBook(input);

for(String authorName: input.getAuthors){
    Author author = repository.getAuthorByName(authorName);

    if(author == null){
       author = new Author(authorName);
    }

    author.getBooks().add(book);

    book.getAuthors.add(author);
}

2) You may need to perform bookRepository.merge(book);, unless this call is in the same transaction as the one assembling the objects, then bookRepository.saveOrUpdate(book); should do.

Upvotes: 1

Related Questions