Reputation: 131
I have two entity classes Order and Product with many-to-many relationship (several orders may have the same product as far as stock is not empty and an order may contain multiple products)as follows:
@Entity
@Table(name = "Order_")
public class Order implements Serializable {
.......
@ManyToMany(mappedBy="orders")
private List<Product> products;
.......
}
@Entity
@Table(name = "Product")
public class Product implements Serializable {
.......
@ManyToMany
@JoinTable(name = "product_order",
joinColumns = { @JoinColumn(referencedColumnName="id") },
inverseJoinColumns = { @JoinColumn(referencedColumnName="id") })
private List <Order> orders;
.......
}
Following is the Dao that is used to insert order and product. The products are predefined and I only need to update their quantity. The order is to be inserted as new order. The product_order relationship table has to be generated and data inserted as primary keys from order and product.
public class OrderDao {
public static void insertProductOrder(Order order, List <Product> cart, List<Integer> quantity){
...............
session.beginTransaction();
Query query;
Product pr;
List list;
List <Order> orders = new ArrayList<>();
orders.add(order);
for(int i=0;i<cart.size();i++) {
query = session.createQuery("from Product where id = :pid");
query.setParameter("pid", cart.get(i).getId());
list = query.list();
pr = (Product) list.get(0);
pr.setQuantity(cart.get(i).getQuantity() - quantity.get(i));
cart.get(i).setOrders(orders);
}
order.setProducts(cart);
session.save(order);
session.getTransaction().commit();
}
}'
With this scenario, data is properly inserted into all three tables. But when I try to insert a new order, the data in the relationship table i.e. product_order is overwritten. The record which is overwritten is the one being updated for quantity. This is due to the fact that Hibernate is removing the record from product_order and then inserting it again. What I want is no updation of product_order table as it is not needed. I just want to insert a record into order table, update quantity in the product table and insert order_id and product_id into the product_order table. Thank you in advance.
Upvotes: 2
Views: 810
Reputation: 1803
Hi Guys i struggled similar kind of scenario where even after maintaining CascadeType.PERSIST my mappings were getting lost/overridden from the mapping table I learned the hard way to fix this issue
I am providing the similar kind of scenario hope it may be helpful to some people.
i am taking Product and Order to explain the issue and using uni-directional manyToMany mapping
@Entity
@Table(name="Product")
public class Product {
@Id
@Column(name = "id")
private Long id;
@Column(name = "product")
private String product;
@ManyToMany(cascade = CascadeType.PERSIST,fetch= FetchType.EAGER)
@JoinTable(name = "product_order_mapping", joinColumns = { @JoinColumn(name = "product_id") }, inverseJoinColumns = {
@JoinColumn(name = "order_id") })
@JsonProperty("orders")
private Set<Order> orders =new HashSet<Order>();
//setters and getters
}
@Table(name="Order")
public class Order {
@Id
@Column(name = "id")
private Long id;
@Column(name = "order")
private String order;
//setters and getters
//equals and hashcode
}
productList and OrderFunctions are some list with list of products and orders details
for (Product pEntity : productList) {
OrderFunctions = this.getAllLineFunctions(product.getId(), cmEntity.getId())
.getBody();
Set<Order> oList = new HashSet<>();
for (OrderFunction orderFn : OrderFunctions) {
Order orderEntity = new Order();
orderEntity.setId(lfs.getOrderFunction_id());
orderEntity.setStageGroup(lfs.getOrderFunctionOrder());
oList.add(sgEntity);
}
orderRepository.saveAll(oList);
pEntity.setOrders(oList);
productRepository.save(pEntity);
}
}
Suppose Product is under a Company Now a Company has multiple Product And Product has Multiple Order
Now Let us take a practical example for storing data in tables
set1--> company with id c1 has Product with id p1,p2,p3 product p1 has order o1,o2,o3 product p2 has order o1,o2 product p3 has order o2,o3,o4
set2--> company with id c2 has Product with id p1,p3 product p1 has order o1,o2 product p3 has order o2
Now when save set1 table product_order_mapping looks like
product_id order_id
---------------------
p1 o1
p1 o2
p1 o3
p2 o1
p2 o2
p3 o2
p3 o3
p3 o4
But when save set2 after set1 table product_order_mapping will look like
product_id order_id
---------------------
p1 o1
p1 o2
p2 o1
p2 o2
p3 o2
We can see the difference before saving set2 and after saving set2 mappings p1->o3 , p3->o3 and p3->o4 are lost
when we tried to store set2 we tried to override the duplicate entry like p1->o1,p1->o2 which are allready available in the mapping table So what happened is before adding these duplicate entry all mappings related to p1 are removed and then p1->o1,p1->o2 got added
And so we lost some previous entry
Avoid adding duplicate entry from set2 like p1->o1,p1->o2 as they are already present in mapping table
for (Company cEntity : companyList) {
for (Product pEntity : productList) {
OrderFunctions = this.getAllOrderFunctions(cEntity.getId(), pEntity.getId());
Set<Order> oList = new HashSet<>();
for (OrderFunction orderFn : OrderFunctions) {
Order orderEntity = new Order();
orderEntity.setId(lfs.getOrderFunction_id());
orderEntity.setStageGroup(lfs.getOrderFunctionOrder());
oList.add(sgEntity);
}
Set<Order> collectSG = pEntity.getOrders().stream().filter(o->oList.contains(o)).collect(Collectors.toSet());
oList.removeAll(collectSG);
if(oList.size()>0) {
orderRepository.saveAll(oList);
pEntity.setOrders(oList);
productRepository.save(pEntity);
}
}
}
}
Upvotes: 1
Reputation: 131
Got it working by properly identifying the owner entity and making changes as follows:
@Entity
@Table(name = "Order_")
public class Order implements Serializable {
.......
@ManyToMany
@Cascade({CascadeType.PERSIST})
@JoinTable(name = "product_order",
joinColumns = { @JoinColumn(referencedColumnName="id") },
inverseJoinColumns = { @JoinColumn(referencedColumnName="id") })
private List<Product> products;
.......
}
@Entity
@Table(name = "Product")
public class Product implements Serializable {
.......
@Cascade({CascadeType.PERSIST})
@ManyToMany(mappedBy="products")
private List <Order> orders;
.......
}
Upvotes: 2