2

我正在努力使用 JPA Criteria API 来为我的数据结构制定查询。好的,我的实体如下。我有用户和组(都共享一个公共基类 OrgEntity)。从逻辑上讲,用户当然可以是多个组的成员。最后,我有一个代表任务的实体,它有一个潜在所有者列表(可以是单个用户或整个组)。域模型总结如下并给出,所以我无法更改。

@Entity
@Inheritance(strategy=InheritanceType.JOINED)
abstract public class OrgEntity {
   @Id
   public String name;
   ...
}

@Entity
public class User extends OrgEntity {
   public String displayName;

   @ManyToMany(mappedBy="members")
   public List<Group> groups;   
   ...
}

@Entity
public class Group extends OrgEntity {
   @ManyToMany
   public List<User> members;
   ...
}

@Entity
public class Task {
   @Id
   public String uuid;

   @ManyToMany
   public List<OrgEntity> potentialOwners;

   ...
}

我的查询的起点是 User 的单个实例。我想知道用户是潜在所有者的所有任务(无论用户是直接包含在 potentialOwners 集合中还是包含在 potentialOwners 中的组的成员中)。

我第一次尝试使用命名查询如下

SELECT DISTINCT t FROM Task AS t JOIN t.potentialOwners po 
WHERE (po IN (SELECT g FROM User u JOIN u.groups g WHERE u = :user) 
       OR po IN (SELECT u FROM User u WHERE u = :user))

它有效,但我不知道这是否是最有效的方法。有什么建议么?

但是,我不知道如何使用标准 API 来实现这一点。有人可以帮我吗。

谢谢

4

1 回答 1

4

好的,我终于想出了如何做到这一点。如果您对我的解决方案感兴趣,就在这里。u 是 User 对象,基本上是查询参数,em 是 EntityManager 实例。

CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();

// specifies the result value of the query
CriteriaQuery<Task> cq = criteriaBuilder.createQuery(Task.class);        
// start with the navigation at the task entity
Root<Task> from = cq.from(Task.class);
// join the potential owner organizational entities
Join<Task,OrgEntity> potentialOwners = from.join("potentialOwners");        
// select the tasks but remove duplicates
CriteriaQuery<Task> select = cq.select(from).distinct(true);

// definition for subquery1: fetch the user instance
Subquery<User> subquery1 = cq.subquery(User.class);
// start at the User entities
Root<User> from1 = subquery1.from(User.class);
// select the whole user
subquery1.select(from1);
// based on the specified user
subquery1.where(criteriaBuilder.equal(from1, u)); 

// definition for subquery2: fetch all groups for given user
Subquery<Group> subquery2 = cq.subquery(Group.class);
// we start at the User entity
Root<User> from2 = subquery2.from(User.class);
// join to Group entities via the groups collection
Join<User, Group> groups = from2.join("groups");
// select the group entities only
subquery2.select(groups).distinct(true);
// and finally restrict to all groups of the specified user
subquery2.where(criteriaBuilder.equal(from2, u));

// order in descending order based on the unique task id
select.orderBy(criteriaBuilder.desc(from.get("uuid")));

// here we restrict to those tasks that have the potential
// owners either in the result set of subquery2 or subquery1
// additionally I've tried to filter for another restriction
// in the task (based on a like statement of the uuid)
select.where(criteriaBuilder.and(
        criteriaBuilder.or(
            criteriaBuilder.in(potentialOwners).value(subquery2), 
            criteriaBuilder.in(potentialOwners).value(subquery1)),
        criteriaBuilder.like(from.<String>get("uuid"), "1%")));


TypedQuery<Task> typedQuery = em.createQuery(select);
List<Task> resultList = typedQuery.getResultList();
于 2013-11-06T23:48:21.793 回答