A
A
ANDREW_TUR2017-09-09 11:27:34
MySQL
ANDREW_TUR, 2017-09-09 11:27:34

Many to many - Hibernate removes the relationship (record in the join table) when updating the entity record. What's wrong?

There is a Many to many relationship - Hibernate removes the relationship (record in the linking table "PRODUCT_ORDER") when updating the record in the entity (in this example it is "PRODUCT") with mapping annotations (meaning @Join table...)
Let's say there is such a database ( test simplified example):

MySQL code
CREATE DATABASE IF NOT EXISTS `WEBSHOP` DEFAULT CHARACTER SET UTF8 COLLATE UTF8_GENERAL_CI;
USE `WEBSHOP`;

CREATE TABLE `PRODUCT` (
  `ID` BIGINT(20) NOT NULL AUTO_INCREMENT,
  `NAME` VARCHAR(255),
  `DESCRIPTION` VARCHAR(255),
  `PRICE` INT(11),
  PRIMARY KEY (`ID`)
)
  COLLATE='UTF8_GENERAL_CI'
  ENGINE=INNODB
;
CREATE TABLE `ORDER` (
  `ID` BIGINT(20) NOT NULL AUTO_INCREMENT,
  `START_ADRESS` VARCHAR(255),
  `END_ADRESS` VARCHAR(255),
  PRIMARY KEY (`ID`)
)
  COLLATE='UTF8_GENERAL_CI'
  ENGINE=INNODB
;
CREATE TABLE `PRODUCT_ORDER` (
  `PRODUCT_ID` BIGINT(20) NOT NULL,
  `ORDER_ID` BIGINT(20) NOT NULL,
  PRIMARY KEY (`PRODUCT_ID`, `ORDER_ID`),
  CONSTRAINT `FK_PRODUCT` FOREIGN KEY (`PRODUCT_ID`) REFERENCES `PRODUCT` (`ID`),
  CONSTRAINT `FK_ORDER` FOREIGN KEY (`ORDER_ID`) REFERENCES `ORDER` (`ID`)
)
  COLLATE='UTF8_GENERAL_CI'
  ENGINE=INNODB
;


There are two entities in the code:
First code. Product - When this record is updated, the link is deleted - a record from the linking table `PRODUCT_ORDER`
package com.blackside.group.entity;

import org.hibernate.annotations.*;

import javax.persistence.*;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.Table;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;

@Entity
@Table(name = "`PRODUCT`")
public class Product implements Serializable {

  private static final long serialVersionUID = 1919474471074343742L;

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  @Column(name = "`ID`", nullable = false)
  private long id;

  @Column(name = "`NAME`")
  private String name;

  @Column(name = "`DESCRIPTION`")
  private String description;

  @Column(name = "`PRICE`")
  private int price;

  @ManyToMany(fetch = FetchType.LAZY, cascade = javax.persistence.CascadeType.ALL)
  @JoinTable(name = "`PRODUCT_ORDER`",
      joinColumns = {@JoinColumn(name = "`PRODUCT_ID`")},
      inverseJoinColumns = {@JoinColumn(name = "`ORDER_ID`")})
  private Set<Order> orders = new HashSet<Order>();

  public Product() {
  }

  public Product(String name, String description, int price) {
    this.name = name;
    this.description = description;
    this.price = price;
  }

  public long getId() {
    return id;
  }

  public String getName() {
    return name;
  }

  public String getDescription() {
    return description;
  }

  public int getPrice() {
    return price;
  }

  public Set<Order> getOrders() {
    return orders;
  }

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

  public void setName(String name) {
    this.name = name;
  }

  public void setDescription(String description) {
    this.description = description;
  }

  public void setPrice(int price) {
    this.price = price;
  }

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

  @Override
  public String toString() {
    return "Product{" +
        "id=" + id +
        ", name='" + name + '\'' +
        ", description='" + description + '\'' +
        ", price=" + price +
        '}';
  }
}


And the second one:
Second code. Order
package com.blackside.group.entity;
@Entity
@Table(name = "`ORDER`")
public class Order implements Serializable {

  private static final long serialVersionUID = 5031143999897706901L;

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  @Column(name = "`ID`", nullable = false)
  private long id;

  @Column(name = "`START_ADRESS`")
  private String startAdress;

  @Column(name = "`END_ADRESS`")
  private String endAdress;


@ManyToMany(cascade = javax.persistence.CascadeType.ALL, mappedBy = "orders")
  private Set<Product> products = new HashSet<Product>();

  public Order() {
  }

  public Order(String startAdress, String endAdress) {
    this.startAdress = startAdress;
    this.endAdress = endAdress;
  }

  public long getId() {
    return id;
  }

  public String getStartAdress() {
    return startAdress;
  }

  public String getEndAdress() {
    return endAdress;
  }

  public Set<Product> getProducts() {
    return products;
  }


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

  public void setStartAdress(String startAdress) {
    this.startAdress = startAdress;
  }

  public void setEndAdress(String endAdress) {
    this.endAdress = endAdress;
  }

  public void setProducts(Set<Product> products) {
    this.products = products;
  }

  @Override
  public String toString() {
    return "Order{" +
        "id=" + id +
        ", startAdress='" + startAdress + '\'' +
        ", endAdress='" + endAdress + '\'' +
        '}';
  }
}
Question: what did I miss? Where did you go wrong?
If it helps then here is the
Structure:
Click to expand
da506e47338a49d7beaa04c0c08add5b.jpg

HibernateConfig code:
Click to expand
package com.blackside.group.config;

@Configuration
@EnableTransactionManagement
@PropertySource(value = {"classpath:application.properties"})
@ComponentScan({"com.blackside.group"})
public class HibernateConfig {


  @Autowired
  private Environment environment;

  @Bean(name = "dataSource")
  public DriverManagerDataSource getDataSource() {
    DriverManagerDataSource dataSource = new DriverManagerDataSource();
    dataSource.setDriverClassName(environment.getRequiredProperty("jdbc.driverClassName"));
    dataSource.setUrl(environment.getRequiredProperty("jdbc.url"));
    dataSource.setUsername(environment.getRequiredProperty("jdbc.username"));
    dataSource.setPassword(environment.getRequiredProperty("jdbc.password"));
    return dataSource;
  }

  @Bean
  public Properties getHibernateProperties() {
    Properties properties = new Properties();
    properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect"));
    properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql"));
    properties.put("hibernate.use_sql_comments", environment.getRequiredProperty("hibernate.use_sql_comments"));
    properties.put("hibernate.format_sql", environment.getRequiredProperty("hibernate.format_sql"));
    properties.put("hibernate.id.new_generator_mappings", environment.getRequiredProperty("hibernate.id.new_generator_mappings"));
    properties.put("hibernate.hbm2ddl.auto", environment.getRequiredProperty("hibernate.hbm2ddl.auto"));
    return properties;
  }

  @Bean
  public LocalSessionFactoryBean sessionFactory() {
    LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
    sessionFactory.setDataSource(getDataSource());
    sessionFactory.setPackagesToScan(new String[] { "com.blackside.group.entity" });
    sessionFactory.setHibernateProperties(getHibernateProperties());
    return sessionFactory;
  }

  @Bean
  @Autowired
  public HibernateTransactionManager hibernateTransactionManager(SessionFactory sessionFactory) {
    return new HibernateTransactionManager(sessionFactory);
  }

  @Bean
  public ProductDAO getProductDAO() {
    return new ProductDAOImpl();
  }
  @Bean
  public OrderDAO getOrderDAO() {
    return new OrderDAOImpl();
  }


}


ProductController code:
Click to expand
package com.blackside.group.controller;

@Controller
public class ProductController {

  @Autowired
  @Qualifier("productService")
  private ProductService productService;

  @RequestMapping(value = "/product", method = RequestMethod.GET)
  public String getListProduct(ModelMap model) {
    List<Product> productList = productService.getAll();
    model.addAttribute("productList", productList);
    return "product";
  }

  @RequestMapping(value = "/product/new", method = RequestMethod.GET)
  public String addProduct(ModelMap model) {
    model.addAttribute("action", "Add new");

    Product product = new Product();
    model.addAttribute("product", product);

    return "productCreate";
  }

  @RequestMapping(value = { "/product/new" }, method = RequestMethod.POST)
  public String saveProduct(Product product) {

    productService.add(product);
    return "redirect:/product";
  }

  @RequestMapping(value = { "/product/delete/{idProduct}" }, method = RequestMethod.GET)
  public String deleteProduct(@PathVariable long idProduct) {
    productService.delete(idProduct);
    return "redirect:/product";
  }

  @RequestMapping(value = {  "/product/edit/{idProduct}" }, method = RequestMethod.GET)
  public String editProduct(@PathVariable long idProduct, ModelMap model) {
    model.addAttribute("action", "Edit");

    Product product = productService.get(idProduct);
    model.addAttribute("product", product);
    model.addAttribute("edit", true);
    return "productForm";
  }

  @RequestMapping(value = {  "/product/edit/{idProduct}" }, method = RequestMethod.POST)
  public String updateProduct(Product product) {
    productService.update(product);
    return "redirect:/product";
  }
}


ProductDaoImpl Code:
Click to expand
package com.blackside.group.dao;
@Repository
public class ProductDAOImpl implements ProductDAO {

  @Autowired
  private SessionFactory sessionFactory;

  private Session getCurSes() {
    return sessionFactory.getCurrentSession();
  }

  public void add(Product item) {
    getCurSes().save(item);
  }

  public void update(Product item) {
    getCurSes().merge(item);
  }

  public void delete(long itemId) {
    Product product = get(itemId);
    if (product != null) getCurSes().delete(product);
  }

  public Product get(long itemId) {
    Product product = (Product) getCurSes().get(Product.class, itemId);
    return product;
  }
  public List<Product> getAll() {
    Criteria criteria = getCurSes().createCriteria(Product.class);
    return criteria.list();
  }
}

Answer the question

In order to leave comments, you need to log in

1 answer(s)
A
ANDREW_TUR, 2017-09-09
@ANDREW_TUR

I solved the problem like this:
I pulled the object from the session and scored it through setters....

public void update(Order item) {
//			getCurSes().merge(item);

    Order entity = (Order) getCurSes().get(Order.class, item.getId());
    if(entity!=null){
      entity.setStartAdress(item.getStartAdress());
      entity.setEndAdress(item.getEndAdress());
    }
  }

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question