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 に答える