'Bulk update with hibernate

Currently we have two endpoints in our API :

  • One to update one entity
  • An various ones to update one field of a Collection of entity

The first one only use saveOrUpdate method of hibernate

While the second one create a custom HQL query to update the desired field.

I would like to make only one endpoint. The idea would be receiving a payload representing the entity. Each field of the entity that are not null would be field that we should update.

I wanted to do that in this way, but it doesn't work as setParameter could set parameters that are not in the String. Any ideas ?

  public long update(Collection<Long> toUpdate, SaleItemDTO newValues) {
    if (toUpdate.size() == 0) return 0;
    StringBuilder hql = new StringBuilder("UPDATE SaleItem SET ");
    if (!newValues.getName().isEmpty()) hql.append("name = :name,");
    if (newValues.getPrice() != null) hql.append("price = :price,");
    if (newValues.getTag() != null) hql.append("tag = :tag,");
    if (newValues.getCategory() != null) hql.append("category.id = :categoryId,");
    if (newValues.isRecurringSale() != null) hql.append("isRecurringSale = :isRecurringSale,");
    if (newValues.isCallProduct() != null) hql.append("callProduct = :callProduct,");
    hql.deleteCharAt(hql.length() - 1).append(" WHERE id in :ids");
    
    return this.sessionFactory
        .getCurrentSession()
        .createQuery(hql.toString())
        .setParameter("name", newValues.getName())
        .setParameter("price", newValues.getPrice())
        .setParameter("tag", newValues.getTag())
        .setParameter("categoryId", newValues.getCategory().getId())
        .setParameter("isRecurringSale", newValues.isRecurringSale())
        .setParameter("callProduct", newValues.isCallProduct())
        .setParameter("ids", toUpdate)
        .executeUpdate();
  }


Solution 1:[1]

Okay, fix it with Criteria API

  public long update(Collection<Long> toUpdate, SaleItemDTO newValues) {
    if (toUpdate.size() == 0) return 0;
    CriteriaBuilder criteriaBuilder = this.sessionFactory.getCriteriaBuilder();
    // create update
    CriteriaUpdate<SaleItem> update = criteriaBuilder.createCriteriaUpdate(SaleItem.class);
    // set the root class
    Root<SaleItem> saleItemRoot = update.from(SaleItem.class);
    // set update and where clause
    if (!newValues.getName().isEmpty()) update.set("name", newValues.getName());
    if (newValues.getPrice() != null) update.set("price", newValues.getPrice());
    //if (newValues.getCategory() != null) update.set("category.id", newValues.getCategory().getId());
    if (newValues.getTag() != null) update.set("tag", newValues.getTag());
    if (newValues.isRecurringSale() != null) update.set("isRecurringSale", newValues.isRecurringSale());
    if (newValues.isCallProduct() != null) update.set("callProduct", newValues.getProduct());
    update.where(saleItemRoot.get("id").in(toUpdate));

    return this.sessionFactory.getCurrentSession().createQuery(update).executeUpdate();
  }

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Paul Serre