Home > OS >  Bidirectional Entities - Overwriting an object in database and hibernate is doing insert instead of
Bidirectional Entities - Overwriting an object in database and hibernate is doing insert instead of

Time:10-26

I have an issue when trying to update the contents of a cart with new values added one by one. I am using Spring boot with Hibernate, JPA Repositories, MySQL Database and a front-end built with vanilla JS.I will describe my issue in the following lines.

I am having an user entity that looks like this:

@Entity
@Table(name = "users")
@Getter
@Setter
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String username;

    private String password;

    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(name = "user_role", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "role_id"))
    private Set<Role> roles;


    @Column(name = "cartprod_id")
    @OneToMany(cascade = {CascadeType.ALL})
    private List<CartItem> cartProduct;

This entity has a List<CartItem> field that looks like this:

@Entity
@Getter
@Setter
public class CartItem {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @Column(name = "product_id")
    private int productId;
    @JsonIgnore
    @ManyToOne
    private User user;
}

And the relationship between them in the Database looks like in this image: enter image description here

The idea of the above code is to have a way to keep the state of the products Cart of an user.

The flow is as follows :

I am doing a request from the front-end each time a user adds a product in the cart, when this happens, I am saving the contents of the cart(that consist of only the products ID's) in the database using the CartItem entity.

The problem

With this approach, instead of saving only the last product added to the cart(or replace the cart completely with the new values similar to an update), it is inserting the same object over and over again but with all the new appended values instead of overwriting the old object(table) in the database. An example of this would be in this first image . As you can see I have added a product to the cart with id 327 first.

enter image description here

Next I am adding a product with id 328 but it also adds 327 a second time, this goes on and on, the more products I add. This last code snippet contains my controller code .

 @PostMapping("/savecart")
    public ResponseEntity<String> saveCartToDb(@RequestBody List<CartItem> cartItemList, Principal principal){
        System.out.println(cartItemList);
        User logedInUser = userService.findUserByUsername(principal.getName()).get();

        List<CartItem> cartItem = logedInUser.getCartProduct();
        if(cartItem.isEmpty()){
            logedInUser.setCartProduct(cartItemList);
            userService.saveNewUser(logedInUser);
        }else {
            cartItem = cartItemList;
            logedInUser.setCartProduct(cartItem);
            userService.saveNewUser(logedInUser);
        }
//        userService.saveNewUser(logedInUser);
        return ResponseEntity.ok().body("ASD");
    }

How can I overwrite the contents of the List<CartItems> for the user so that I will not append new and old values again and again ? Would a SET help as it won't allow duplicates ?

I have also tried this How do I update an entity using spring-data-jpa? but I a not sure that I need to create a @Query for this issue.

CodePudding user response:

I managed to make it work. The solution is the following.

This is a bidirectional one-to-many / many-to-one issue. In order to be able to remove child elements from the parent, we need to decouple(detach) them from the parent. Since parent and child are bound together by a foreign key the detachment has to be done on both ends. If one has a reference to the other this will not work so BOTH REFERENCES have to be removed. 2 methods are needed and both need to be called when doing decoupling. This is what I used.

private Set<CartProduct> cartProduct;

This one to be added in the parent class (User).

 public void removeChild(CartProduct child) {
        this.cartProduct.remove(child);
    }

This one to be added in the Child class

  public void removeParent() {
        this.user.removeChild(this);
        this.user = null;
    }

Methods also have to be called like this

   for(CartProduct cartItem : cartItemList){
                cartItem.removeParent();
                logedInUser.removeChild(cartItem);
            }
  • Related