如何使用 JPA 读取集合 属性?
How to read a collection property with JPA?
我有两个 classes,Account
和 Admin
,具有多对多映射。
Admin
class 有一个 Account
class 的集合,反之亦然。
我想写一个查询,给定帐户 ID,return 所有帐户管理员。
这里是Account
class的相关字段:
@Entity
public class Account {
@Id
public Long id;
@ManyToMany(mappedBy = "account", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
public List<Admin> users = new ArrayList<>();
}
我已经尝试使用 multiselect
对 Admin.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>
不是一个实体。
我希望这是有道理的。
我有两个 classes,Account
和 Admin
,具有多对多映射。
Admin
class 有一个 Account
class 的集合,反之亦然。
我想写一个查询,给定帐户 ID,return 所有帐户管理员。
这里是Account
class的相关字段:
@Entity
public class Account {
@Id
public Long id;
@ManyToMany(mappedBy = "account", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
public List<Admin> users = new ArrayList<>();
}
我已经尝试使用 multiselect
对 Admin.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>
不是一个实体。
我希望这是有道理的。