使用CriteriaQuery API进行多态JPA查询

我有以下实体结构:

+-----------+ +-------------+ | User | -------------> | Role | +-----------+ +-------------+ ^ | +-------+---------+ | | +-----------+ +-----------+ +------------+ | Role1 | | Role2 |--------> | SomeEntity | +-----------+ +-----------+ +------------+ 

我想得到其Role2具有SomeEntity并具有特定属性值的所有用户的名称。 我需要使用JPA标准API执行此操作。

到目前为止我做的是:

 CriteriaBuilder cb = ... CriteriaQuery query = cb.createQuery(String.class); Root user = query.from(User.class); SetJoin userRolesJoin = user.join(User_.roles); // As you can see the userRolesJoin is of type Role and a Role doesn't have // an property someEntity. So how to "cast" the userRolesJoin into an // SetJoin. 

如何在这里进行多态查询? 有什么建议么?

不幸的是,JPA标准API并不像Hibernate的critera API那样直观。

使用子查询解决了它

我创建了一个基于Role2类型的子查询,将其与“SomeEntity”实体连接并应用了谓词。 然后我使用与子查询谓词匹配的Role2.ids将子查询连接到“main”查询。

 CriteriaBuilder cb = ... CriteriaQuery query = cb.createQuery(String.class); Root user = query.from(User.class); SetJoin userRolesJoin = user.join(User_.roles); Path roleIdPath = userRolesJoin.get(User_.id); Subquery subquery = query.subquery(String.class); Root role2Root = subquery.from(Role2.class); Join someEntityJoin = role2Root.join(Role2_.someEntity); Path someEntityPropertyPath = someEntityJoin.get(SomeEntity_.aProperty); Predicate someEntityPropertyPredicate = cb.equal(someEntityPropertyPath, "a property value"); subquery.select(role2Root.get(Role2_.id)); subquery.where(someEntityPropertyPredicate); In idInSubqueryIds = cb.in(roleIdPath).value(subquery); query.select(user.get(User_.username)); query.where(idInSubqueryIds); EntityManager entityManager = ...; TypedQuery query = entityManager.createQuery(query); List usernames = query.getResultList(); 

您可以在Criteria中使用as()进行强制转换。

 ((Path)user.join(User_.roles).as(Role2.class)).join(Role2_.someEntity) 

这可能是JPA 2.1之前提供者特定的,但我认为它是JPA 2.1中的标准。

在JPQL中,您可以使用TREAT操作。

http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Querying/JPQL#Special_Operators

你也可以使用第二个来自(),

 Root role2 = query.from(Role2.class); ... cb.equal(user.join(User_.roles), role2)