4

I new to hibernate and I don't why I am having this error. I commented out my DAO code for updating and hibernate is still executing an update query. Here is my code for my service.

@Override
@Transactional(readOnly = false)
public void updateProduct(Product productToUpdate) throws DuplicateProductException {

    Product product = productDao.findByProductId(productToUpdate.getProductId());

    if (productDao.findByName(productToUpdate.getName()) != null
            && !product.getName().equals(productToUpdate.getName())) {
        throw new DuplicateProductException();
    }

    product.setName(productToUpdate.getName());
    product.setCategory(productToUpdate.getCategory());
    product.setPrice(productToUpdate.getPrice());
    product.setImage(productToUpdate.getImage());

//      productDao.updateProduct(product);
   }

I commented the DAO out and hibernate is still executing the query.

Here is the code for my controller.

@RequestMapping(value = "/updateProduct", method = RequestMethod.POST)
public String updateProductPost(@Validated @ModelAttribute("product") ProductHelper productHelper,
        BindingResult bindingResult, Model model) throws CategoryNotFoundException {

    model.addAttribute("categories", categoryService.findAll());
    model.addAttribute("activePage", AdminPage.UPDATE_PRODUCT);

    updateProductValidator.validate(productHelper, bindingResult);

    if (bindingResult.hasErrors()) {
        return "admin_home";
    }

    Product product = productHelper.buildProductToUpdate(productService, categoryService);

    try {

        productService.updateProduct(product);
        model.addAttribute("updatedProduct", product);
    } catch (DuplicateProductException e) {

        model.addAttribute("duplicateProduct", product);
    }

    return "admin_home";
}

What's weird is that I've got my entire DAO code commented out:

//  @Override
//  public void updateProduct(Product product) {
////        sessionFactory.getCurrentSession().update(product);
//  }

And still hibernate is executing an update query:

Hibernate: update PRODUCT set category_id=?, image=?, name=?, price=?, product_id=? where id=?
Hibernate: select product0_.id as id1_3_, product0_.category_id as category6_3_, product0_.image as image2_3_, product0_.name as name3_3_, product0_.price as price4_3_, product0_.product_id as product_5_3_ from PRODUCT product0_ where product0_.product_id=?
Hibernate: select product0_.id as id1_3_, product0_.category_id as category6_3_, product0_.image as image2_3_, product0_.name as name3_3_, product0_.price as price4_3_, product0_.product_id as product_5_3_ from PRODUCT product0_ where product0_.name=?

If this is some beginner mistake, I am really sorry but I'm fairly new to hibernate. Thank you.

Neil Stockton
  • 11,383
  • 3
  • 34
  • 29
saluyotamazing
  • 107
  • 1
  • 9
  • When an entity is attached and you change one of its properties, Hibernate automatically saves the changes you made to the corresponding row in the database (at flush/commit time). http://stackoverflow.com/questions/5260297/how-does-the-detached-object-work-in-hibernate – Kamil Nękanowicz Nov 17 '16 at 18:53
  • How do I fix this? This is my first time encountering this problem. I've never had problems with updates before. – saluyotamazing Nov 17 '16 at 19:03
  • Possible duplicate of [Transactional saves without calling update method](http://stackoverflow.com/questions/8190926/transactional-saves-without-calling-update-method) – daredesm Nov 17 '16 at 23:40

1 Answers1

3

JPA uses managed entities. That means that whatever changes you make to a managed entity within a session are persisted when that session is closed or flushed.

Workaround you can create new instance by copy constructor:

Product productDetached = new Product(productDao.findByProductId(productToUpdate.getProductId()))
//you can change and do not worry about sql query
productDetached.setName(productToUpdate.getName());

If you don't want that behavior, you need to manually detach the entity.

If you are using JPA 2.0, you can use EntityManager#detach() to detach a single entity from persistence context. Also, Hibernate has a Session#evict() which serves the same purpose:

Since JpaRepository doesn't provide this functionality itself, you can add a custom implementation, something like this:

public interface UserRepositoryCustom {

    ...
   void detachUser(User u);
    ...
}

public interface UserRepository extends JpaRepository<User, Long>, UserRepositoryCustom {
    ...
}

@Repository
public class UserRepositoryCustomImpl implements UserRepositoryCustom {
    ...
    @PersistenceContext
    private EntityManager entityManager;

    @Override
    public void detachUser(User u) {
        entityManager.detach(u);
    }
    ...
}
Community
  • 1
  • 1
Kamil Nękanowicz
  • 6,254
  • 7
  • 34
  • 51
  • voted up because this is the right answer. JPA manages the entity state, when you change it (like you did with your 'sets') it will persist the next time it interacts with that entity. This is why View Models exist. To separate your DAO and Entities from state change for viewing purposes. – Gabriel Reiser Dec 06 '16 at 20:51