子类属性的JPA Criteria API过滤

时间:2019-08-30 23:30:38

标签: jpa hibernate-criteria

我具有以下实体域。

父类

@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
}

儿童班级

@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 + "%"));
            }
        };
    }

该规范未能说明Event不包含名为“ searchTerm”的属性,因为只有在SearchEvent子类中存在该属性,这才有意义。

我在这里JPA2 Criteria queries on entity hierarchy处查看了此答案,因为涉及查询的实体位于类层次结构之外,因此无法解决我的问题。

作为本机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'

更新31/08/2019

我查看了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 + "%"));
            }
        };
    }

1 个答案:

答案 0 :(得分:0)

在JPA Crtieria API中很难使用Hibernate中的各种继承策略。

代替使用相当复杂的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...);