I have two classes connected with many-to-many relationship:
Book.java
@Entity
@Table(name = "book")
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "book_id")
private Long id;
@Column(nullable = false)
private String title;
private String description;
@Column(name = "release_date")
@Temporal(TemporalType.TIMESTAMP)
private Date releaseDate;
@JoinColumn(name = "cover_image")
@OneToOne(cascade = CascadeType.MERGE)
private UploadFile coverImage;
@OneToOne(cascade = CascadeType.MERGE)
private UploadFile content;
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name = "book_category", joinColumns = {@JoinColumn(name = "book_id", referencedColumnName = "id")},
inverseJoinColumns = {@JoinColumn(name = "category_id", referencedColumnName = "id")})
private Set<Category> categories;
}
Category.java
@Entity
@Table(name = "category")
public class Category {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "category_id")
private Long id;
@Column(name = "category_name")
private String name;
@ManyToMany(mappedBy = "categories", fetch = FetchType.LAZY) // I also tried an option with adding cascade = CascadeType.ALL
private List<Book> books;
}
When I want to add book to database I recive following exception:
org.springframework.dao.InvalidDataAccessApiUsageException: detached entity passed to persist: com.github.model.Category; nested exception is org.hibernate.PersistentObjectException: detached entity passed to persist: com.github.model.Category
Interestingly removing @GeneratedValue annotation from the Category class causes everything to work as well as possible. To add book I extends JpaRepository:
public interface Repository extends JpaRepository<Book, Long>{
}
and then
Repository repository;
repository.save(book);
What's also should be important I'm using h2 database. To see all the code you can visit my github: https://github.com/mmaciula/Library/tree/master/src/main/java/com/github
EDIT
After I added @Column annotations the problem with InvalidDataAccessApiUsageException
was solved. However, the problem with mapping collection appears. Here is the stack track I receive:
java.lang.IllegalStateException: Failed to load ApplicationContext
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is org.hibernate.AnnotationException: Unable to map collection com.github.model.Book.categories
Caused by: org.hibernate.AnnotationException: Unable to map collection com.github.model.Book.categories
Caused by: org.hibernate.cfg.RecoverableException: Unable to find column with logical name: id in org.hibernate.mapping.Table(book) and its related supertables and secondary tables
Caused by: org.hibernate.MappingException: Unable to find column with logical name: id in org.hibernate.mapping.Table(book) and its related supertables and secondary tables
EDIT 2
When I changed referencedColumnName
in @JoinTable from id to book_id I recived DataIntegrityViolationException shown below:
org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint ["FKAM8LLDERP40MVBBWCEQPU6L2S: PUBLIC.BOOK_CATEGORY FOREIGN KEY(CATEGORY_ID) REFERENCES PUBLIC.CATEGORY(CATEGORY_ID) (1)"; SQL statement:
insert into book_category (book_id, category_id) values (?, ?) [23506-196]]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement