A dynamic filter centralizes a restriction that would otherwise have to be repeated in queries. For example, a user may see only items whose seller has an equal or lower ranking. The restriction is defined in mapping metadata, but takes its parameter value from the current unit of work. section 13.4 section 13.4.1
Set up and use the filter in three steps:
- Define a uniquely named @FilterDef, with any @ParamDef declarations, on an entity or in package-info.java. A definition alone is inactive. section 13.4.1
- Apply @Filter to each entity or collection to restrict. Its condition is an SQL expression that must be true for a row to pass; a defaultCondition can avoid repeating the same expression. section 13.4.2 section 13.4.4
- For the unit of work, call em.unwrap(Session.class).enableFilter("limitByUserRanking") and setParameter("currentUserRanking", ranking). Set every declared parameter before querying. section 13.4.3
Restrict items by seller ranking
Apply @Filter(name = "limitByUserRanking", condition = ":currentUserRanking >= (select u.RANKING from USERS u where u.ID = SELLER_ID)") to Item. With currentUserRanking set to 0, Hibernate appends the condition to generated SQL for JPQL and criteria queries, excluding items sold by higher-ranked users. The unqualified SELLER_ID refers to the table mapped by Item. section 13.4.2 section 13.4.3
The same filter can restrict iteration over Category.items when applied to that collection. In the example, ranking 0 loads one item; ranking 100 loads two. Filter.validate() detects an unset parameter, while setParameterList() supplies values for conditions such as SQL IN. section 13.4.4 section 13.4.3
Do not treat this as a blanket access-control check. Filters do not apply to retrieval by identifier, such as em.find(Item.class, id): that lookup may be satisfied from the first-level persistence-context cache. They also do not filter many-to-one or one-to-one association access. section 13.4.3
Shows the SQL condition attached directly to the Item mapping. section 13.4.2
Path: Ch13/dynamic/src/main/java/com/manning/javapersistence/ch13/filtering /dynamic/Category.java @Entity public class Category { @OneToMany(mappedBy = "category") @org.hibernate.annotations.Filter( name = "limitByUserRanking", condition = """ :currentUserRanking >= ( select u.RANKING from USERS u where u.ID = SELLER_ID )""" ) private Set<Item> items = new HashSet<>(); // . . . }
Shows where to attach the same restriction when collection access must also be filtered. section 13.4.4
