Duplicate association elements when merge

Hi,

I’ve got a unidirectional association between a Product entity and its categories. It’s something like this:

@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name = "...", joinColumns = @JoinColumn(name = "product_id"),
           inverseJoinColumns = @JoinColumn(name = "category_id"))
	public Set<Category> getCategories() {
		return categories;
	}

equals and hashcode methods are implemented inside the Category class.

In my application, I have a detached product instance that I apply the categories changes to. My first approach was the following one:

product.getCategories().clear();
product.getCategories().addAll(newCategories);

session.merge(product);

If for example my product was in categories [A, B, C], and now I set to just [B], the merge would issue a SQL insert for B, violating the primary key because B was already associated with the product.

So I changed the code updating the product to this:

product.setCategories(new HashSet<>(newCategories));

session.merge(product);

And that problem is no longer happening. However, I thought clearing and adding the values to the existing collection was the preferred approach, to not replace the existing specific Hibernate implementation (PersistentBag or whatever it is).

Could somebody tell me what was wrong with the first alternative? Is the second one the correct way to manage this?

Thanks in advance

Neither approach is good. As explained in this article, you should do the collection merge so that:

  • you remove the existing database records that are no longer found in the incoming collection.
  • you update the existing database records which can be found in the incoming collection.
  • you add the records found in the incoming collection, which cannot be found in the current database snapshot.