0

I have problem with my application. Currently I have Vehicles and Order table having many to many relationship. The problem is when I get input from front-end, the staging table for order_vehicle does not update. I am not sure how the many to many works in SpringBoot and there is annotation I have added such as @JsonIgnore which if not added I will have infinite recursive JSON. I keep trying to solve my problem but couldn't. I am using Hibernate 5.2 and do reverse engineering from my database.

Order.java

package com.jdm.entity;
// Generated 11-Dec-2019 10:05:44 by Hibernate Tools 5.2.12.Final
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

import com.fasterxml.jackson.annotation.JsonBackReference;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonManagedReference;

/**
 * Order generated by hbm2java
 */
@Entity
@Table(name = "order", catalog = "crud")
public class Order implements java.io.Serializable {

    private OrderId id;
    private Date date;
    private Float total;

    @JsonIgnore
    private Customer customer;
    @JsonIgnore
    private Employee employee;
    //@JsonIgnore
    private Set<Vehicle> vehicles = new HashSet<Vehicle>(0);

    public Order() {
    }

    public Order(OrderId id, Customer customer, Employee employee) {
        this.id = id;
        this.customer = customer;
        this.employee = employee;
    }

    public Order(OrderId id, Customer customer, Employee employee, Date date, Float total, Set<Vehicle> vehicles) {
        this.id = id;
        this.customer = customer;
        this.employee = employee;
        this.date = date;
        this.total = total;
        this.vehicles = vehicles;
    }

    @EmbeddedId

    @AttributeOverrides({ @AttributeOverride(name = "OId", column = @Column(name = "o_id", nullable = false)),
            @AttributeOverride(name = "customerCustId", column = @Column(name = "customer_cust_id", nullable = false)),
            @AttributeOverride(name = "employeeEmpId", column = @Column(name = "employee_emp_id", nullable = false)) })
    public OrderId getId() {
        return this.id;
    }

    public void setId(OrderId id) {
        this.id = id;
    }

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "customer_cust_id", nullable = false, insertable = false, updatable = false)
    public Customer getCustomer() {
        return this.customer;
    }

    public void setCustomer(Customer customer) {
        this.customer = customer;
    }

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "employee_emp_id", nullable = false, insertable = false, updatable = false)
    public Employee getEmployee() {
        return this.employee;
    }

    public void setEmployee(Employee employee) {
        this.employee = employee;
    }

    @Temporal(TemporalType.DATE)
    @Column(name = "date", length = 10)
    public Date getDate() {
        return this.date;
    }

    public void setDate(Date date) {
        this.date = date;
    }

    @Column(name = "total", precision = 12, scale = 0)
    public Float getTotal() {
        return this.total;
    }

    public void setTotal(Float total) {
        this.total = total;
    }

    @ManyToMany(fetch = FetchType.LAZY,cascade = {CascadeType.ALL})
//  @JsonBackReference
    @JoinTable(name = "order_has_vehicle", catalog = "crud", joinColumns = {
            @JoinColumn(name = "order_o_id", nullable = false, updatable = false),
            @JoinColumn(name = "order_customer_cust_id", nullable = false, updatable = false),
            @JoinColumn(name = "order_employee_emp_id", nullable = false, updatable = false) }, inverseJoinColumns = {
                    @JoinColumn(name = "vehicle_v_id", nullable = false, updatable = false) })
    public Set<Vehicle> getVehicles() {
        return this.vehicles;
    }

    public void setVehicles(Set<Vehicle> vehicles) {
        this.vehicles = vehicles;
    }

}

OrderId.java

package com.jdm.entity;
// Generated 16-Dec-2019 23:11:42 by Hibernate Tools 5.2.12.Final

import javax.persistence.Column;
import javax.persistence.Embeddable;

/**
 * OrderId generated by hbm2java
 */
@Embeddable
public class OrderId implements java.io.Serializable {

    private int OId;
    private int customerCustId;
    private int employeeEmpId;

    public OrderId() {
    }

    public OrderId(int OId, int customerCustId, int employeeEmpId) {
        this.OId = OId;
        this.customerCustId = customerCustId;
        this.employeeEmpId = employeeEmpId;
    }

    @Column(name = "o_id", nullable = false)
    public int getOId() {
        return this.OId;
    }

    public void setOId(int OId) {
        this.OId = OId;
    }

    @Column(name = "customer_cust_id", nullable = false)
    public int getCustomerCustId() {
        return this.customerCustId;
    }

    public void setCustomerCustId(int customerCustId) {
        this.customerCustId = customerCustId;
    }

    @Column(name = "employee_emp_id", nullable = false)
    public int getEmployeeEmpId() {
        return this.employeeEmpId;
    }

    public void setEmployeeEmpId(int employeeEmpId) {
        this.employeeEmpId = employeeEmpId;
    }

    public boolean equals(Object other) {
        if ((this == other))
            return true;
        if ((other == null))
            return false;
        if (!(other instanceof OrderId))
            return false;
        OrderId castOther = (OrderId) other;

        return (this.getOId() == castOther.getOId()) && (this.getCustomerCustId() == castOther.getCustomerCustId())
                && (this.getEmployeeEmpId() == castOther.getEmployeeEmpId());
    }

    public int hashCode() {
        int result = 17;

        result = 37 * result + this.getOId();
        result = 37 * result + this.getCustomerCustId();
        result = 37 * result + this.getEmployeeEmpId();
        return result;
    }

}

Vehicle.java

package com.jdm.entity;
// Generated 11-Dec-2019 10:05:44 by Hibernate Tools 5.2.12.Final

import java.util.HashSet;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import static javax.persistence.GenerationType.IDENTITY;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;

import com.fasterxml.jackson.annotation.JsonBackReference;
import com.fasterxml.jackson.annotation.JsonIgnore;

/**
 * Vehicle generated by hbm2java
 */
@Entity
@Table(name = "vehicle", catalog = "crud")
public class Vehicle implements java.io.Serializable {

    private Integer VId;
    private String VManufacturer;
    private String VModel;
    private Integer VYear;
    private String VCategory;
    private String VTransmission;
    private Integer VMilleage;
    private String VPlate;
    private String VColor;
    private Float VPrice;


    private Set<Order> orders = new HashSet<Order>(0);

    public Vehicle() {
    }

    public Vehicle(String VManufacturer, String VModel, Integer VYear, String VCategory, String VTransmission,
            Integer VMilleage, String VPlate, String VColor, Float VPrice, Set<Order> orders) {
        this.VManufacturer = VManufacturer;
        this.VModel = VModel;
        this.VYear = VYear;
        this.VCategory = VCategory;
        this.VTransmission = VTransmission;
        this.VMilleage = VMilleage;
        this.VPlate = VPlate;
        this.VColor = VColor;
        this.VPrice = VPrice;
        this.orders = orders;
    }

    @Id
    @GeneratedValue(strategy = IDENTITY)

    @Column(name = "v_id", unique = true, nullable = false)
    public Integer getVId() {
        return this.VId;
    }

    public void setVId(Integer VId) {
        this.VId = VId;
    }

    @Column(name = "v_manufacturer", length = 45)
    public String getVManufacturer() {
        return this.VManufacturer;
    }

    public void setVManufacturer(String VManufacturer) {
        this.VManufacturer = VManufacturer;
    }

    @Column(name = "v_model", length = 45)
    public String getVModel() {
        return this.VModel;
    }

    public void setVModel(String VModel) {
        this.VModel = VModel;
    }

    @Column(name = "v_year")
    public Integer getVYear() {
        return this.VYear;
    }

    public void setVYear(Integer VYear) {
        this.VYear = VYear;
    }

    @Column(name = "v_category", length = 45)
    public String getVCategory() {
        return this.VCategory;
    }

    public void setVCategory(String VCategory) {
        this.VCategory = VCategory;
    }

    @Column(name = "v_transmission", length = 45)
    public String getVTransmission() {
        return this.VTransmission;
    }

    public void setVTransmission(String VTransmission) {
        this.VTransmission = VTransmission;
    }

    @Column(name = "v_milleage")
    public Integer getVMilleage() {
        return this.VMilleage;
    }

    public void setVMilleage(Integer VMilleage) {
        this.VMilleage = VMilleage;
    }

    @Column(name = "v_plate", length = 45)
    public String getVPlate() {
        return this.VPlate;
    }

    public void setVPlate(String VPlate) {
        this.VPlate = VPlate;
    }

    @Column(name = "v_color", length = 45)
    public String getVColor() {
        return this.VColor;
    }

    public void setVColor(String VColor) {
        this.VColor = VColor;
    }

    @Column(name = "v_price", precision = 12, scale = 0)
    public Float getVPrice() {
        return this.VPrice;
    }

    public void setVPrice(Float VPrice) {
        this.VPrice = VPrice;
    }

    @ManyToMany(fetch = FetchType.LAZY)
//  @JsonBackReference
    @JoinTable(name = "order_has_vehicle", catalog = "crud", joinColumns = {
            @JoinColumn(name = "vehicle_v_id", nullable = false, updatable = false) }, inverseJoinColumns = {
                    @JoinColumn(name = "order_o_id", nullable = false, updatable = false),
                    @JoinColumn(name = "order_customer_cust_id", nullable = false, updatable = false),
                    @JoinColumn(name = "order_employee_emp_id", nullable = false, updatable = false) })
    public Set<Order> getOrders() {
        return this.orders;
    }

    public void setOrders(Set<Order> orders) {
        this.orders = orders;
    }

}

OrderServiceImpl.java

package com.jdm.impl;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.jdm.dto.OrderDTO;
import com.jdm.dto.OrderIdDTO;
import com.jdm.dto.VehicleDTO;
import com.jdm.entity.Customer;
import com.jdm.entity.Order;
import com.jdm.entity.OrderId;
import com.jdm.entity.Vehicle;
import com.jdm.repository.CustomerRepository;
import com.jdm.repository.OrderRepository;
import com.jdm.repository.VehicleRepository;
import com.jdm.services.CustomerService;
import com.jdm.services.OrderService;

@Service
public class OrderServiceImpl implements OrderService{

    @Autowired
    private OrderRepository orderRepo;

    @Autowired
    private VehicleRepository vehicleRepo;

    public List<Order> findAllOrder(){  
        return (List<Order>) orderRepo.findAll();
    }

    public Optional<Order> findOrderById(Integer id) {  
        return orderRepo.findById(id);
    }

    public Order saveOrder(OrderDTO orderdto) {

        Order order = new Order();
        OrderId oid = new OrderId();

        oid.setOId(orderdto.getId().getOId());
        oid.setEmployeeEmpId(orderdto.getId().getEmployeeEmpId());
        oid.setCustomerCustId(orderdto.getId().getCustomerCustId());
        order.setId(oid);

        order.setDate(orderdto.getDate());
        order.setTotal(orderdto.getTotal());
//      order.setVehicles(orderdto.getVehicles());

//      Vehicle vehicle = new Vehicle();
//      vehicle.getOrders().add(order);

//      Set<Order> orderlist = new HashSet<Order>();
//      Vehicle v = new Vehicle();
//      orderlist.add(order);
//      v.setOrders(orderlist);


        Set<Vehicle> vehiclelist = new HashSet<Vehicle>();
        vehicleRepo.findAll().forEach(vehiclelist::add);

        for(Vehicle v: vehiclelist) {
            Set<Vehicle> vehicle = new HashSet<Vehicle>();
            Vehicle vdto = new Vehicle();
            vdto.setVId(v.getVId());
            vdto.setVManufacturer(v.getVManufacturer());
            vdto.setVModel(v.getVModel());
            vdto.setVYear(v.getVYear());
            vdto.setVMilleage(v.getVMilleage());
            vdto.setVPlate(v.getVPlate());
            vdto.setVTransmission(v.getVTransmission());
            vdto.setVColor(v.getVColor());
            vdto.setVCategory(v.getVCategory());
            vdto.setVPrice(v.getVPrice());

            order.getVehicles().add(vdto);

//          Set<Order> orderlist = new HashSet<Order>();
//          orderlist.add(order);
//          v.setOrders(orderlist);
        }

        return orderRepo.save(order);
    }

    public void deleteOrder(Integer id) {
        orderRepo.deleteById(id);
    }

    public void updateOrder(Order order) {      
        orderRepo.save(order);
    }
}

ERD Diagram

enter image description here

Roshan Dx
  • 39
  • 5
  • 1
    You wonder why the join table doesn't update while you set `updatable = false` on literally every `@JoinColumn`? – XtremeBaumer Dec 18 '19 at 10:09
  • Hi, so sorry since I am new to Hibernate. So I should change the value of updatable = true ? I did reverse engineering so I assume Hibernate do the configuration automatically. Correct me if I am wrong l. – Roshan Dx Dec 18 '19 at 10:13
  • Set them to true and it should work – XtremeBaumer Dec 18 '19 at 10:16

1 Answers1

0

Like @XtremeBaumer said, you need to remove the updatable=false attribute for updation to work. The attribute is normally used when you want to tell a bidirectional relation that the owning side of the relation will be responsible for the updation .

For instance, in your case suppose your Employee or Customer table has an Address entity.So in the address entity class ,suppose you have a One to Many relation with the Employee or Customer entity.In this case , you could provide the updatable=false attribute on the Employee or Customer entity class in the Address entity to tell Hibernate that it is not the responsibility of the Address entity class to update the Customer or Employee entities.

Also, you need to define the owning side of the relation in your code correctly.In your code , you are providing the join condition in both the entity classes. Read.

Also, in you code the Entity class is being directly returned from the endpoint. It is advisable to return a DTO object from your service class instead of the Entity class itself, so that you could prevent the infinite reference or have better control over the data returned. If you want to know more about DTO pattern, read.

Ananthapadmanabhan
  • 5,706
  • 6
  • 22
  • 39