Polymorphic JPA query with CriteriaQuery API

前端 未结 2 1776
爱一瞬间的悲伤
爱一瞬间的悲伤 2021-01-02 22:53

I have the following entity structure:

   +-----------+                +-------------+        
   |  User     | -------------> |    Role     |
   +-------         


        
相关标签:
2条回答
  • 2021-01-02 23:52

    Solved it using a subquery

    I created a subquery based on the Role2 type, joined it with the "SomeEntity" entity and applied the predicates. Then I connected the subquery to the "main" query using the Role2.ids that match the subquery predicates.

    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();
    
    0 讨论(0)
  • 2021-01-02 23:52

    You can use as() in Criteria to cast.

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

    This may be provider specific previous to JPA 2.1, but I think it is standard in JPA 2.1.

    In JPQL you can use the TREAT operation.

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

    You can also use a second from(),

    Root<Role2> role2 = query.from(Role2.class);
    ... cb.equal(user.join(User_.roles), role2)
    
    0 讨论(0)
提交回复
热议问题