0

How can a many to many mapping be done in Quarkus when using hibernate-reactive-panache extension together with reactive-pg-client. I tried it, failed terribly and resorted to the non-reactive way of implementing it. Here is my non-reactive way of implementing it.

@Entity
@Table(name = "categories")
public class CategoryEntity extends PanacheEntityBase{

    //some code here

    @Fetch(FetchMode.JOIN)
    @ManyToMany(mappedBy = "categories")
    @JsonManagedReference
    public Set<ProductEntity> products = new HashSet<>();

    public void addProduct(ProductEntity product){
        boolean added = products.add(product);
        if(added){
            product.categories.add(this);
        }
    }

    @Transactional
    public static void create(Category category){
        CategoryEntity entity = new CategoryEntity();
        entity.description = category.description;
        entity.name = category.name;

        ProductEntity pe = ProductEntity.findByName(category.productName);
        if(pe != null){
            pe.addCategory(entity);
        } 
      
        entity.persistAndFlush();
    }

Here is the ProductEntity...

@Table(name = "products")
@Entity
public class ProductEntity extends PanacheEntityBase{

    @Fetch(FetchMode.JOIN)
    @ManyToMany(
        cascade = {
            CascadeType.PERSIST, 
            CascadeType.MERGE,
            CascadeType.DETACH,
            CascadeType.REFRESH
        })
    @JoinTable(
        name = "product_category",
        joinColumns = {@JoinColumn(name = "product_id")},
        inverseJoinColumns = {@JoinColumn(name = "category_id")},
        uniqueConstraints = {
            @UniqueConstraint(columnNames = {"product_id", "category_id"})
        }
    )
    @JsonBackReference
    public Set<CategoryEntity> categories = new HashSet<>();


    public void addCategory(CategoryEntity category){
        boolean added = categories.add(category);
        if(added){
            category.products.add(this);
        }
    }

    public static ProductEntity findByName(String name){
        return find("name", name).firstResult();
    }

    @Transactional
    public static void create(Product product){
        ProductEntity entity = new ProductEntity(
            product.name, product.imageURL, product.description, product.status, product.price
        );

        CategoryEntity ce = CategoryEntity.findByName(product.categoryName);
        if(ce != null){
            ce.addProduct(entity);
        }
        

        entity.persistAndFlush();
    }

The main roadblock that I faced when I implemented it in a reactive way was I could not call a category from the database in order to link it with a product I was creating. Not that the code couldn't compile it just couldn't run. When creating a product I wrote the following code...

    public static Uni<ProductEntity> create(Product product){
        ProductEntity entity = new ProductEntity(
            product.name, product.imageURL, product.description, product.status, product.price
        );

        //this adding of a category could not work i.e a category in the database 
        //would not be retrieved to be linked with the product I was creating.
        CategoryEntity.findByName(product.categoryName)
        .onItem().transform(category -> entity.addCategory(category));

       return entity.persistAndFlush();

I also tried

CategoryEntity cEntity = CategoryEntity.findByName(product.categoryName).await().indefinitely();
productEntity.addCategory(cEntity);

I would be surprised with a runtime error even after annotating the method with @Blocking

NOTE: I have some pojos, Product and Category. The Product POJO has a categoryName, and the Category POJO has a productName. I use them when creating new products and categories.

Thanks for your help in advance.

0 Answers0