使用CriteriaQuery API进行多态JPA查询

Ren*_*ink 6 java api jpa

我有以下实体结构:

   +-----------+                +-------------+        
   |  User     | -------------> |    Role     |
   +-----------+                +-------------+
                                       ^
                                       |
                               +-------+---------+
                               |                 |
                        +-----------+      +-----------+           +------------+
                        |   Role1   |      |  Role2    |-------->  | SomeEntity |
                        +-----------+      +-----------+           +------------+
Run Code Online (Sandbox Code Playgroud)

我想获取其Role2具有SomeEntity并具有特定属性值的所有User的名称.我需要使用JPA标准API执行此操作.

到目前为止我所做的是:

CriteriaBuilder cb = ...
CriteriaQuery<String> query = cb.createQuery(String.class);
Root<User> user = query.from(User.class);
SetJoin<User, Role> 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<User, Role2>.
Run Code Online (Sandbox Code Playgroud)

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

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

Ren*_*ink 6

使用子查询解决了它

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

CriteriaBuilder cb = ...
CriteriaQuery<String> query = cb.createQuery(String.class);
Root<User> user = query.from(User.class);
SetJoin<User, Role> userRolesJoin = user.join(User_.roles);
Path<String> roleIdPath = userRolesJoin.get(User_.id);

Subquery<String> subquery = query.subquery(String.class);
Root<Role2> role2Root = subquery.from(Role2.class);
Join<Role2, SomeEntity> someEntityJoin = role2Root.join(Role2_.someEntity);
Path<String> someEntityPropertyPath = someEntityJoin.get(SomeEntity_.aProperty);
Predicate someEntityPropertyPredicate = cb.equal(someEntityPropertyPath,
            "a property value");
subquery.select(role2Root.get(Role2_.id));
subquery.where(someEntityPropertyPredicate);

In<String> idInSubqueryIds = cb.in(roleIdPath).value(subquery);

query.select(user.get(User_.username));
query.where(idInSubqueryIds);

EntityManager entityManager = ...;
TypedQuery<String> query = entityManager.createQuery(query);
List<String> usernames = query.getResultList();
Run Code Online (Sandbox Code Playgroud)