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.