我有以下实体结构:
+-----------+ +-------------+
| User | -------------> | Role |
+-----------+ +-------------+
^
|
+-------+---------+
| |
+-----------+ +-----------+ +------------+
| Role1 | | Role2 |--------> | SomeEntity |
+-----------+ +-----------+ +------------+
我希望得到其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>.
如何在这里进行多态查询?有什么建议吗?
不幸的是,JPA标准API并不像Hibernate的critera API那样直观。
答案 0 :(得分: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();
答案 1 :(得分:2)
您可以在标准中使用as()进行投射。
((Path)user.join(User_.roles).as(Role2.class)).join(Role2_.someEntity)
这可能是JPA 2.1之前的提供商特定,但我认为它是JPA 2.1中的标准。
在JPQL中,您可以使用TREAT操作。
你也可以使用第二个来自(),
Root<Role2> role2 = query.from(Role2.class);
... cb.equal(user.join(User_.roles), role2)