Search code examples
javahibernatejpaormmany-to-many

Update existing records in Hibernate ManyToMany Relation


In my database I have two tables Book and Label with ManyToMany relation between them. I have mapped them successfully in Hibernate using annotation of ManyToMany with CascadeALL.

Now consider this scenario.

When I add a new Book with labels list. The list of label contain existing and new labels both. When the book is saved in the database it creates duplicate entries of existing labels. [Means each time a new label will be created (even for existing labels)with different primary key,rather than using the reference of existing and updating ManyToMany Table] .I want Hibernate to update existing labels and create new ones. Similarly ManyToMany table to be updated itself.

I can think of solution of doing it manually.

  • Save the Book without labels.
  • Separating the existing and new labels with book reference, from Book labels.
  • Update the existing labels using session.update() and save the new using session.save()
  • The ManyToMany table will be automatically updated.

But I believe this is solution involve little lengthy coding and unnecessary processing, and can be improved.

Is there Hibernate provide some builtin feature to cater this problem and how my solution can be improved.

Here goes my Book Entity

@Entity
@XmlRootElement
public class Book {
@Id
@GeneratedValue
private int bookID;
private String bookName;
private String bookDescription;
private String bookAuthor;
private String bookEdition;
private String bookDownloadURL;
private String bookImageURL;

@ManyToMany(cascade = { CascadeType.ALL })
@JoinTable(name = "book_label", joinColumns = { @JoinColumn(name = "books_bookID") }, inverseJoinColumns = {
        @JoinColumn(name = "labels_labelID") })
private List<Label> labels = new ArrayList<Label>();
//getters and setters

Label Entity

@Entity
@XmlRootElement
public class Label {

@Id
@GeneratedValue
private int labelID;
private String labelName;
private String labelDesc;
@ManyToMany(mappedBy="labels",fetch=FetchType.EAGER)
private List<Book> books = new ArrayList<Book>();
// getter and setters

In my database I have three tables created already

  1. book table with col name exactly same as datamembers of Book entity
  2. label table with col name exactly same as datamembers of Label entity
  3. book_label table with two column books_bookID, labels_labelID. These column are referencing bookID and labelID from other two tabels respectively (means they are foreign keys actually)

And here is my test case code

    BookDAO booksDao = new BookDAO();
    LabelDAO labelDao = new LabelDAO();

    //Label by these name exist already in database. 
    //Upon adding the new book it should use the previous label and do entries in manytomany table accordingly
    // (shouldn't create new labels with same names and map against them) <- THis is happening now 

    Label label1= new Label();
    label1.setLabelName("Fantasy");

    Label label2= new Label();
    label2.setLabelName("Literature");


    Book book1= new Book();
    book1.setBookName("Talaash");
    book1.getLabels().add(label1);
    book1.getLabels().add(label2);

    booksDao.addBook(book1);

Solution

  • If I understand correctly, your problem is that both tables are owners of the relationship, so this results in duplicate entries. Only one class should be owner of the relationship. In one of yout class try something like:

    @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, mappedBy = "books")
    public List<Label> getLabels()
    

    and in your label you should have books list. Again this is if i understand correctly because you do not provide the classes so that we have a better analysis