子类属性的JPA Criteria API过滤 [英] JPA Criteria API filtering on subclasses' attribute

查看:142
本文介绍了子类属性的JPA Criteria API过滤的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我具有以下实体域.

父类

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

I'm trying to retrieve any SupportModuleInteractions that contain a SearchEvent containing a keyword.

这是我用来尝试检索那些SupportModuleInteractions的规范:

This is the Specification I'm using to try and retrieve those 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子类中.

The Specification fails saying that Event contains no attribute called "searchTerm" which makes sense as that's present only on the SearchEvent subclass.

我在这里查看了此答案关于实体层次结构的JPA2标准查询不能解决我的问题,因为查询中涉及的实体位于类层次结构之外.

I've looked at this answer here JPA2 Criteria queries on entity hierarchy which doesn't solve my issue as the entity involved in the query lies outside the class hierarchy.

作为本机SQL查询,这就是我要达到的目标:

As a native SQL query, this is what I'm trying to acheive:

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标准API:子类的查询属性并修改了规范以使用criteriaBuilder.treat(...)没有运气:

I've looked at JPA Criteria API: query property of subclass and revised the Specification to use criteriaBuilder.treat(...) with no luck:

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

推荐答案

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

The various inheritance strategies in Hibernate are rather difficult to work with in the JPA Crtieria API.

而不是使用非常复杂的treat()(请参阅

Instead of using treat(), which is rather finicky (see HHH-9862 and related issues), generate a subquery() expression which filters for searchTerm and add that to your parent query.

您的总体实现尚不清楚,因此我创建了一个基本示例:

Your overall implementation is unclear, so I created a basic example:

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...);

这篇关于子类属性的JPA Criteria API过滤的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆