问题描述:

Hibernate uses to classes to represent literals:

  • org.hibernate.jpa.criteria.expression.LiteralExpression
  • org.hibernate.jpa.criteria.expression.NullLiteralExpression

The first one will put a placeholder into the query and apply UserTypes to the value, the second one will simply put null into the query, thereby ignoring any configured UserType. CriteriaUpdateImpl will choose NullLiteralExpression if passed a null as second parameter to set(Path<Y>, X) and CriteriaBuilderImpl.literal(T) refuses null-values all together.

We use a UserType which stores Calendar-objects as AES-encrypted date-strings and are forced to replace null-values by 0-length data for compatibility reasons.

So the question is whether there is any way to archive the following using only JPA-APIs with a Hibernate-backend, as this is really ugly

CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();

CriteriaUpdate<Entity> criteriaUpdate = criteriaBuilder.createCriteriaUpdate(Entity.class);

Root<Entity> root = criteriaUpdate.from(Entity.class);

criteriaUpdate.where(criteriaBuilder.equal(root.get("id"), id));

setPathToNull((CriteriaBuilderImpl) criteriaBuilder, criteriaUpdate, root.get("value"));

Query query = entityManager.createQuery(criteriaUpdate);

LOG.info("About to perform 2. update");

LOG.info("Updated " + query.executeUpdate() + " entities");

Helper:

private <Y> CriteriaUpdate<Entity> setPathToNull(CriteriaBuilderImpl criteriaBuilder, CriteriaUpdate<Entity> criteriaUpdate, Path<Y> value) {

return criteriaUpdate.set(value, new LiteralExpression<>(criteriaBuilder, (Y)null));

}

A full working example is provided at

https://github.com/TheConstructor/NullUpdate/tree/master/src/main/java/tc/vom

You may come up with other ways of accessing the property, but the property-name is provided as String and the entity can not be loaded beforehand, as this update is part of an reading-value-error-clean-up. If the name of the column would help you, it can be used as well.

相关阅读:
Top