我有两个类,Account
和Admin
,具有多对多映射。Admin
类有一个Account
类的集合,反之亦然。
我想编写一个查询,给定帐户 ID,将返回所有帐户管理员。
以下是Account
类的相关字段:
@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:无法在类[模型。管理员]。预期参数为:java.util.Collection [选择新模型。来自模型的管理员(生成别名0.users(。帐户作为生成的别名0,其中生成别名0.id=1L]"(此处为1L,可能是因为我用1作为accountId调用此函数(,由QuerySyntaxException
消息"无法在类[模型。管理员]。预期的参数是: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();
}
之后,我尝试运行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
导致编译错误,说实际返回值List<List<Admin>>>
并且与签名不匹配。
此方法抛出了一个不同的异常,一个带有消息的NonUniqueResultException
:"result 返回多个元素"。
在调试时,我尝试typedQuery.getResultList()
计算表达式,发现它实际上返回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
返回的值与实际返回值不同?
当您仔细查看数据库时,也许这是有意义的。TypeQuery
返回实体,因此基本上是表中的行。List<Admin>
是实体的集合,因此即使您的Account
具有List<Admin>
作为字段,查询仍将返回List<Admin>
实体,而不是List<List<Admin>>
,因为List<Admin>
不是实体。
我希望这是有道理的。