0

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
mariusz
  • 157
  • 2
  • 16
  • seems like you just need to add CascadeType.ALL as the cascade type for that relationship. That should make it work @ManyToMany(mappedBy = "categories", fetch = FetchType.LAZY, cascadeType=CascadeType.ALL) – GSUgambit Oct 03 '18 at 05:57
  • @GSUgambit I tried to add `CascadeType.ALL` but still got an exception. – mariusz Oct 03 '18 at 06:01
  • maybe you should add the cascade type to the category side. The root of your problem is that the category is not persisted so it cannot save the book to a "detached" [unsaved / managed by hibernate] category. Typically casecade type solves this. Sorry I'm a bit sleepy but maybe adding it to the other class will help you. Otherwise, you should persist the category before trying to persist the book though I don't think you should have to do that. – GSUgambit Oct 03 '18 at 06:07
  • After adding cascade type to Category side I got another exception: `org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint ["FKAM8LLDERP40MVBBWCEQPU6L2S: PUBLIC.BOOK_CATEGORY FOREIGN KEY(CATEGORY_ID) REFERENCES PUBLIC.CATEGORY(ID) (2)"; SQL statement: insert into book_category (book_id, category_id) values (?, ?) [23506-196]]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement` – mariusz Oct 03 '18 at 06:16
  • i see you have referenced columns in your table but the posted code doesnt have the annotation needed on the ids. change AT to the annotation (it thinks im trying to tag people) In book you should ATColumn(name = "book_id") ATId ATGeneratedValue(strategy = GenerationType.IDENTITY) private Long id; And in category ATColumn(name = "category_id") ATId ATGeneratedValue(strategy = GenerationType.IDENTITY) private Long id; – GSUgambit Oct 03 '18 at 06:22
  • You may want to rethink your relationship of books to categories. I'd imagine that you wouldn't want your books to dynamically generate categories... rather use categories that are prepopulated... – shinjw Oct 03 '18 at 07:21
  • Well adding the @Column annotations solved InvalidDataAccessApiUsageException problem. But something is still not right with mapping collections. I edited my post and add stack trace of new exceptions I recived. – mariusz Oct 03 '18 at 07:59

1 Answers1

0

Possible solution 1 : remove (cascade = CascadeType.ALL)

Possible solution 2 : add (cascade = CascadeType.ALL) in @ManyToMany(mappedBy = "categories", fetch = FetchType.LAZY,cascade = CascadeType.ALL)

Refer this : https://stackoverflow.com/a/45781533/6572971

Alien
  • 15,141
  • 6
  • 37
  • 57