首页 > 解决方案 > Hibernate bi-directional @ManyToAny mapping

问题描述

I have two entities ProductEntity and CategoryEntity and they both have a many-to-many relationship. It all works fine - I can call product.getCategories() and category.getProducts() and it returns correctly. And more importantly I can add a Category to a Product and a Product to a Category and then save them and it all works fine.

Now I want to add a new entity DocumentEntity that also has a collection of CategoryEntity. For that reason I introduce a parent entity called AbstractCategorizableEntity and have both ProductEntity and CategoryEntity to extend from it.

Then the mapping becomes like this:

public class CategoryEntity {

    @JoinTable(name = "categorizable_category", joinColumns = @JoinColumn(name = "category_id"), inverseJoinColumns = @JoinColumn(name = "categorizable_id"))
    @ManyToAny(fetch = FetchType.LAZY, metaDef = AbstractCategorizableEntity.META_DEF_NAME, metaColumn = @Column(name = "categorizable_type"))
    private Set<AbstractCategorizableEntity> categorizables;

}
public class AbstractCategorizableEntity {

    @JoinTable(name = "categorizable_category", joinColumns = @JoinColumn(name = "categorizable_id"), inverseJoinColumns = @JoinColumn(name = "category_id"))
    @ManyToMany(fetch = FetchType.LAZY, targetEntity = CategoryEntity.class, cascade = { CascadeType.MERGE })
    private Set<CategoryEntity> categories;

}

Now reading works fine. Also writing works fine when writing from the category side:

CategoryEntity category = new CategoryEntity();
category.setCategorizables(Sets.newHashSet(product, document));
entityManager.persist(category); // <---- WORKS FINE

However if I try to save the product and set the category I get an exception:

ProductEntity product = new ProductEntity();
product.setCategories(Sets.newHashSet(category1));
entityManager.persist(product); //<----- EXCEPTION HAPPENS

I get an exception that

2020-12-03 22:43:22,524 [main] ERROR: Referential integrity constraint violation: "FK1LY02CXDDJEEXOA2WQL85NTAW: PUBLIC.ABSTRACT_CATEGORIZABLE_PRODUCT FOREIGN KEY(ABSTRACT_CATEGORIZABLE_ID) REFERENCES PUBLIC.PRODUCT(ID) (142152297423644336)"; SQL statement:
insert into categorizable_category (abstract_categorizable_id, category_id) values (?, ?) [23506-200]

It seems that it cannot save it because I am not passing the metaColumn.

My questions is: how can I map a many-to-many relation with polymorphic entities? How can I pass the meta-column when saving the product?

标签: hibernatejpa

解决方案


You have 3 options:

  • Use SINGLE_TABLE or JOINED inheritance for AbstractCategorizableEntity
  • Disable the foreign key generation
  • Just declare abstract getters and setter in AbstractCategorizableEntity and use dedicated join tables for every subtype for categories

推荐阅读