title: Joining three tables with @ManyToMany association
body: <p>Joining three tables with the @ManyToMany association</p>
  
  <p>I am implementing a Book Store application using Spring Boot and Spring Data JPA. I have tried this with @onetoone and @manytoone and @onetomany associations but I'm stuck with the @ManyToMany association. </p>
  
  <p>There are three tables - Book, Genre, and Author. I want to do the following
  1) Create a new table - Book_Genre_Author
  2) If the Author or Genre already exists in the database, it does not make a new entry in the database.
  3) If Book already exists in the database, it does not make an entry into the database.
  4) How to implement insert &amp; update operations using Spring Data JPA?</p>
  
  <p>Here are my three entities - </p>
  
  <pre><code>@Entity
  @Table(name = "Book_Details")
  public class Book {
  
  @Id
  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "CUSTOM_SEQUENCE")
  @SequenceGenerator(sequenceName = "customer_seq", allocationSize = 1, name = "CUSTOM_SEQUENCE")
  @Column(name = "BookId")
  int bookId;
  
  public int getBookId() {
      return bookId;
  }
  
  public void setBookId(int bookId) {
      this.bookId = bookId;
  }
  
  @Column(name = "BookName")
  String bookName;
  
  
  
  @ManyToMany(cascade=CascadeType.ALL)
  @JoinTable(name = "Book_Author_Genre", joinColumns = @JoinColumn(name = "bookId"), inverseJoinColumns = @JoinColumn(name = "genreId"))
  @MapKeyJoinColumn(name = "authorId")
  @ElementCollection
  private Map&lt;Author, Genre&gt; authorGenre = new HashMap&lt;&gt;();
  
  public Map&lt;Author, Genre&gt; getAuthorGenre() {
      return authorGenre;
  }
  
  public void setAuthorGenre(Map&lt;Author, Genre&gt; authorGenre) {
      this.authorGenre = authorGenre;
  }
  
  @Column(name = "Language")
  String language;
  
  
  
  @Column(name = "GoodReadReviews")
  String goodReadReviews;
  
  
    @Override public String toString() { return "BookId=" + this.bookId +
    "::BookName=" + this.bookName + "::AuthorId=" + "Will check how to get it" +
    "::Langauge = " + this.language + "::GenreId = " + "Will check how to get it" +
    "::GoodReadReviews=" + this.goodReadReviews;
  
    }
  
  
  public String getBookName() {
      return bookName;
  }
  
  public void setBookName(String bookName) {
      this.bookName = bookName;
  }
  
  public String getLanguage() {
      return language;
  }
  
  public void setLanguage(String language) {
      this.language = language;
  }
  
  public String getGoodReadReviews() {
      return goodReadReviews;
  }
  
  public void setGoodReadReviews(String goodReadReviews) {
      this.goodReadReviews = goodReadReviews;
  }
  </code></pre>
  
  <p>}</p>
  
  <pre><code>@Entity
  @Table(name="Author_Details")
  public class Author {
  
  @Id
  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator="AuthorSeqGenerator")
  @SequenceGenerator(sequenceName = "author_seq", allocationSize = 1, name = "AuthorSeqGenerator")
  @Column(name="AuthorId")
  int authorId;
  
  @Column(name="AuthorName")
  String authorName;
  
  @Column(name="Country")
  String country;
  
  @Column(name="Gender")
  String gender;
  
  
  public int getAuthorId() {
      return authorId;
  }
  public void setAuthorId(int authorId) {
      this.authorId = authorId;
  }
  
  
  public String getAuthorName() {
      return authorName;
  }
  public void setAuthorName(String authorName) {
      this.authorName = authorName;
  }
  public String getCountry() {
      return country;
  }
  public void setCountry(String country) {
      this.country = country;
  }
  public String getGender() {
      return gender;
  }
  public void setGender(String gender) {
      this.gender = gender;
  }
  </code></pre>
  
  <p>}</p>
  
  <pre><code>@Entity
  @Table(name="Genre_details")
  public class Genre {
  
  @Id
  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator="GenreSeqGenerator")
  @SequenceGenerator(sequenceName = "genre_seq", allocationSize = 1, name = "GenreSeqGenerator")
  int genreId;
  
  @Column(name="GenreName")
  String genreName;
  
  public int getGenreId() {
      return genreId;
  }
  
  public void setGenreId(int genreId) {
      this.genreId = genreId;
  }
  
  
  
  
  public String getGenreName() {
      return genreName;
  }
  
  public void setGenreName(String genreName) {
      this.genreName = genreName;
  }
  </code></pre>
  
  <p>}</p>
  
  <p>I tried saving book details using the following code - </p>
  
  <pre><code>Author author = new Author();
          author.setAuthorName("Rabindranath Tagore");
          author.setCountry("India");
          author.setGender("Male");
  
      Genre genre = new Genre();
      genre.setGenreName("Fiction");
  
      Book book = new Book();
      book.setBookName("Gitanjali");
      book.setGoodReadReviews("5");
      book.setLanguage("Bengali");
      HashMap&lt;Author,Genre&gt; authorGenre = new HashMap&lt;&gt;();
      authorGenre.put(author, genre);
      book.setAuthorGenre(authorGenre);
  
      bookRepository.save(book);
  </code></pre>
  
  <p>But I'm receiving below error.</p>
  
  <p><strong><em>Caused by: org.springframework.dao.InvalidDataAccessApiUsageException: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.bsm.app.model.Author; nested exception is java.lang.IllegalStateException: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.bsm.app.model.Author</em></strong></p>
  
  <p>I might be wrong in my approach as I'm naive in it. Please suggest and support.</p>