如何使用 JPA 读取集合 属性?

How to read a collection property with JPA?

我有两个 classes,AccountAdmin,具有多对多映射。 Admin class 有一个 Account class 的集合,反之亦然。

我想写一个查询,给定帐户 ID,return 所有帐户管理员。

这里是Accountclass的相关字段:

@Entity
public class Account {

    @Id
    public Long id;

    @ManyToMany(mappedBy = "account", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    public List<Admin> users = new ArrayList<>();
}

我已经尝试使用 multiselectAdmin.class 进行常规查询,因为每个帐户都有一组管理员,但试图从我的 CriteriaQuery<Admin> 中获取 TypedQuery<Admin>我得到一个 IllegalArgumentException 和消息 "org.hibernate.hql.internal.ast.QuerySyntaxException: Unable to locate appropriate constructor on class [models.Admin]. Expected arguments are: java.util.Collection [select new models.Admin(generatedAlias0.users) from models.Account as generatedAlias0 where generatedAlias0.id=1L]"(这里 1L 可能是因为我用 1 作为 accountId 调用了这个函数),由 QuerySyntaxException 和消息 "Unable to locate appropriate constructor on class [models.Admin]. Expected arguments are: java.util.Collection".

代码:

private static List<Admin> readAccountAdmins(Long accountId) {
    CriteriaBuilder cb = JPA.em().getCriteriaBuilder();
    CriteriaQuery<Admin> cq = cb.createQuery(Admin.class);
    Root<Account> root = cq.from(Account.class);

    Predicate idPredicate = cb.equal(root.get(Account_.id), accountId);
    cq.multiselect(root.get(Account_.users)).where(idPredicate);

    TypedQuery<Admin> typedQuery = JPA.em().createQuery(cq); // exception thrown here
    return typedQuery.getResultList();
}

之后,我尝试 运行 a TypedQuery<List<Admin>>,因为我正在尝试阅读列表。这是尝试查询列表的第一次迭代:

private static List<Admin> readAccountAdmins(Long accountId) {
    CriteriaBuilder cb = JPA.em().getCriteriaBuilder();
    CriteriaQuery<List<Admin>> cq = cb.createQuery((Class<List<Admin>>)(Class<?>)(Collection.class));
    Root<Account> root = cq.from(Account.class);

    Predicate idPredicate = cb.equal(root.get(Account_.id), accountId);
    cq.select(root.get(Account_.users)).where(idPredicate);

    TypedQuery<List<Admin>> typedQuery = JPA.em().createQuery(cq);
    return typedQuery.getSingleResult(); // exception thrown here
}

我使用 getSingleResult 因为 getResultList 导致编译错误,说实际的 return 值是 List<List<Admin>>> 并且与签名不匹配。

此方法引发了一个不同的异常,一个 NonUniqueResultException 消息:"result returns more than one elements".

在调试时,我尝试计算表达式 typedQuery.getResultList() 并发现它实际上是 returns List<Admin> 而不是 List<List<Admin>>,所以我进行了最后一次迭代此功能的数量:

private static List<Admin> readAccountAdmins(Long accountId) {
    CriteriaBuilder cb = JPA.em().getCriteriaBuilder();
    CriteriaQuery<List<Admin>> cq = cb.createQuery((Class<List<Admin>>)(Class<?>)(Collection.class));
    Root<Account> root = cq.from(Account.class);

    Predicate idPredicate = cb.equal(root.get(Account_.id), accountId);
    cq.select(root.get(Account_.users)).where(idPredicate);

    TypedQuery<List<Admin>> typedQuery = JPA.em().createQuery(cq);
    return (List) typedQuery.getResultList();
}

现在,此功能有效,但我的问题是为什么? 为什么编译器决定 getResultList return 与实际 return 值不同?

当您仔细查看您的数据库时,也许它有意义。一个 TypeQuery returns 个实体,所以基本上是表中的行。 List<Admin> 是实体的集合,因此即使您的 Account 有一个 List<Admin> 作为字段,查询仍将 return List<Admin> 个实体,而不是 List<List<Admin>> 因为 List<Admin> 不是一个实体。

我希望这是有道理的。