JPA Criteria API 过滤子类的属性
JPA Criteria API filtering on subclasses' attribute
我有以下实体域。
Parent class
@Entity
public final class SupportModuleInteraction implements Serializable {
@Id
private Long id;
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "supportModuleInteraction")
@OrderColumn
private List<Event> events;
// ... getters/setters/ other attributes ommitted
}
Child class 层次结构
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "event_type")
public abstract class Event implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@ManyToOne(fetch = FetchType.EAGER)
private SupportModuleInteraction supportModuleInteraction;
}
@Entity
@DiscriminatorValue("SEARCH")
public final class SearchEvent extends Event {
@Lob
private String searchTerm;
}
我正在尝试检索任何包含包含关键字的 SearchEvent 的 SupportModuleInteractions。
这是我用来尝试检索那些 SupportModuleInteractions 的规范:
public static Specification<SupportModuleInteraction> interactionWithSearchEventContaingKeyword(String keyword) {
return new Specification<SupportModuleInteraction>() {
@Override
public Predicate toPredicate(Root<SupportModuleInteraction> smi, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
Join<SupportModuleInteraction, SearchEvent> events = smi.join("events");
return criteriaBuilder.and(
criteriaBuilder.equal(events.type(), SearchEvent.class),
criteriaBuilder.like(events.get("searchTerm"), "%" + keyword + "%"));
}
};
}
规范没有说明事件不包含称为 "searchTerm" 的属性,这是有道理的,因为它只存在于 SearchEvent 子 class.
我在这里 JPA2 Criteria queries on entity hierarchy 查看了这个答案,它没有解决我的问题,因为查询中涉及的实体位于 class 层次结构之外。
作为原生 SQL 查询,这就是我要实现的目标:
SELECT *
FROM event E JOIN support_module_interaction smi ON E.support_module_interaction_id = smi.id
WHERE event_type = 'SEARCH'
AND search_term LIKE 'searchString'
2019 年 8 月 31 日更新
我查看了 JPA Criteria API: query property of subclass 并修改了规范以使用 criteriaBuilder.treat(...)
,但没有成功:
public static Specification<SupportModuleInteraction> interactionWithSearchEventContaingKeyword(String keyword) {
return new Specification<SupportModuleInteraction>() {
@Override
public Predicate toPredicate(Root<SupportModuleInteraction> smi, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
Join<SupportModuleInteraction, SearchEvent> events = smi.join("events");
return criteriaBuilder.and(
criteriaBuilder.equal(events.type(), SearchEvent.class),
criteriaBuilder.like(
criteriaBuilder.treat(events.get("searchTerm"), SearchEvent.class).get("searchTerm"),
"%" + keyword + "%"));
}
};
}
Hibernate 中的各种继承策略很难在 JPA Crtieria 中使用 API。
不要使用相当挑剔的 treat()
(请参阅 HHH-9862 和相关问题),而是生成一个 subquery()
表达式来过滤 searchTerm
并将其添加到您的父查询。
您的整体实现不清楚,所以我创建了一个基本示例:
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<SupportModuleInteraction> cq = cb.createQuery(SupportModuleInteraction.class);
Root<SupportModuleInteraction> supModIntRoot = cq.from(SupportModuleInteraction.class);
Join<SupportModuleInteraction, Event> supModIntEventJoin = supModIntRoot.join("events");
// Instantiate the Subquery and Root objects for your subclass entity
Subquery<SearchEvent> searchEventSubquery = cq.from(SearchEvent.class);
Root<SearchEvent> searchEventRoot = searchEventSubquery.from(SearchEvent.class);
// Generate the subquery and filter based on the given parameter
searchEventSubquery.select(searchEventRoot);
searchEventSubquery.where(cb.like(searchEventRoot.get("searchTerm", "%" + searchTerm + "%");
// add subquery to where clause in parent query
cq.select(supModIntRoot);
cq.where(supModIntEventJoin.in(searchEventSubquery), //other subqueries and filters...);
我有以下实体域。
Parent class
@Entity
public final class SupportModuleInteraction implements Serializable {
@Id
private Long id;
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "supportModuleInteraction")
@OrderColumn
private List<Event> events;
// ... getters/setters/ other attributes ommitted
}
Child class 层次结构
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "event_type")
public abstract class Event implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@ManyToOne(fetch = FetchType.EAGER)
private SupportModuleInteraction supportModuleInteraction;
}
@Entity
@DiscriminatorValue("SEARCH")
public final class SearchEvent extends Event {
@Lob
private String searchTerm;
}
我正在尝试检索任何包含包含关键字的 SearchEvent 的 SupportModuleInteractions。
这是我用来尝试检索那些 SupportModuleInteractions 的规范:
public static Specification<SupportModuleInteraction> interactionWithSearchEventContaingKeyword(String keyword) {
return new Specification<SupportModuleInteraction>() {
@Override
public Predicate toPredicate(Root<SupportModuleInteraction> smi, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
Join<SupportModuleInteraction, SearchEvent> events = smi.join("events");
return criteriaBuilder.and(
criteriaBuilder.equal(events.type(), SearchEvent.class),
criteriaBuilder.like(events.get("searchTerm"), "%" + keyword + "%"));
}
};
}
规范没有说明事件不包含称为 "searchTerm" 的属性,这是有道理的,因为它只存在于 SearchEvent 子 class.
我在这里 JPA2 Criteria queries on entity hierarchy 查看了这个答案,它没有解决我的问题,因为查询中涉及的实体位于 class 层次结构之外。
作为原生 SQL 查询,这就是我要实现的目标:
SELECT *
FROM event E JOIN support_module_interaction smi ON E.support_module_interaction_id = smi.id
WHERE event_type = 'SEARCH'
AND search_term LIKE 'searchString'
2019 年 8 月 31 日更新
我查看了 JPA Criteria API: query property of subclass 并修改了规范以使用 criteriaBuilder.treat(...)
,但没有成功:
public static Specification<SupportModuleInteraction> interactionWithSearchEventContaingKeyword(String keyword) {
return new Specification<SupportModuleInteraction>() {
@Override
public Predicate toPredicate(Root<SupportModuleInteraction> smi, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
Join<SupportModuleInteraction, SearchEvent> events = smi.join("events");
return criteriaBuilder.and(
criteriaBuilder.equal(events.type(), SearchEvent.class),
criteriaBuilder.like(
criteriaBuilder.treat(events.get("searchTerm"), SearchEvent.class).get("searchTerm"),
"%" + keyword + "%"));
}
};
}
Hibernate 中的各种继承策略很难在 JPA Crtieria 中使用 API。
不要使用相当挑剔的 treat()
(请参阅 HHH-9862 和相关问题),而是生成一个 subquery()
表达式来过滤 searchTerm
并将其添加到您的父查询。
您的整体实现不清楚,所以我创建了一个基本示例:
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<SupportModuleInteraction> cq = cb.createQuery(SupportModuleInteraction.class);
Root<SupportModuleInteraction> supModIntRoot = cq.from(SupportModuleInteraction.class);
Join<SupportModuleInteraction, Event> supModIntEventJoin = supModIntRoot.join("events");
// Instantiate the Subquery and Root objects for your subclass entity
Subquery<SearchEvent> searchEventSubquery = cq.from(SearchEvent.class);
Root<SearchEvent> searchEventRoot = searchEventSubquery.from(SearchEvent.class);
// Generate the subquery and filter based on the given parameter
searchEventSubquery.select(searchEventRoot);
searchEventSubquery.where(cb.like(searchEventRoot.get("searchTerm", "%" + searchTerm + "%");
// add subquery to where clause in parent query
cq.select(supModIntRoot);
cq.where(supModIntEventJoin.in(searchEventSubquery), //other subqueries and filters...);