能否结合Hibernate Criteria API使用@PostLoad注解?
Short answer: No, you can't directly use a transient property populated via @PostLoad in Hibernate Criteria API queries — here's why and what you can do instead.
Why your @PostLoad approach throws an error
The error org.hibernate.QueryException: could not resolve property: start of: com.entity.EntityExample occurs because:
- Your
startfield is marked@Transient, which tells Hibernate it’s not mapped to any database column and shouldn’t be tracked as a queryable property. - The Criteria API builds queries by translating property references into database-level SQL. Since
startdoesn’t exist in the database (and Hibernate doesn’t recognize it as a valid query target), it can’t resolve the field when constructing the query.
In contrast, @Formula works because Hibernate treats the annotated property as a virtual derived column. It embeds the formula’s SQL expression directly into the generated query, so the database computes the value during the query itself — that’s why the Criteria API can resolve it without issues.
Solutions to work around this
Option 1: Filter in memory (small datasets only)
If you want to keep using @PostLoad, fetch all entities first then filter the transient property in your application code. Note this is only feasible for small datasets, as fetching all rows can hurt performance with large volumes:
public Collection<EntityExample> get(String start) { Session session = getSession(); Criteria criteria = session.createCriteria(EntityExample.class, "entity"); // Fetch all entities from the database List<EntityExample> allEntities = criteria.list(); // Filter using the @PostLoad-populated start property return allEntities.stream() .filter(entity -> !start.equals(entity.getStart())) .collect(Collectors.toList()); }
Option 2: Make @Formula maintenance-friendly
To avoid manual updates to the @Formula value when refactoring underlying columns, centralize the expression logic:
- Define the formula as a static constant in your entity class, so you only update it once if columns change:
@Entity public class EntityExample { private static final String START_COMPUTATION = "start_year::text || start_period::text"; private Integer startYear; private Integer startPeriod; @Formula(value = START_COMPUTATION) private String start; // Getters and setters }
- Alternatively, create a database view that includes the computed
startcolumn, then map your entity to the view instead of the base table. This centralizes the logic in the database, so refactoring table columns only requires updating the view.
Option 3: Use HQL with inline computation
If you don’t want to use @Formula, write an HQL query that computes the start value directly in the query (mirroring how @Formula works):
public Collection<EntityExample> get(String start) { Session session = getSession(); String hql = "FROM EntityExample e WHERE CONCAT(e.startYear, e.startPeriod) != :start"; Query query = session.createQuery(hql); query.setParameter("start", start); return query.list(); }
This way, the computation happens in the database, and you don’t rely on @PostLoad for query filtering.
内容的提问来源于stack exchange,提问作者rogerio_gentil

