我使用的是Spring 3.2.11.RELEASE,Hibernate 4.3.6.Final和JPA 2.1.我有以下实体与以下字段…
@Entity
@Table(name = "user")
public class User implements Serializable, Comparable
{
…
@ManyToMany
@JoinTable(name = "user_organization", joinColumns = { @JoinColumn(name = "USER_ID") }, inverseJoinColumns = { @JoinColumn(name = "ORGANIZATION_ID") })
@LazyCollection(LazyCollectionOption.FALSE)
@SortNatural
private SortedSet organizations;
上面,组织的排序由组织的名称字段完成.当我运行JPA查询来检索User对象时,我想根据与之关联的组织的有序列表进行排序.我试过这个……
final CriteriaBuilder builder = m_entityManager.getCriteriaBuilder();
final CriteriaQuery criteria = builder.createQuery(User.class);
…
final SetJoin orgsJoin = orderByRoot.join(User_.organizations, JoinType.LEFT);
orderByExpr = orgsJoin.get(Organization_.name);
criteria.orderBy(builder.asc(orderByExpr);
但它不适用于用户与多个组织相关联的情况 – 有时在其列表中按字母顺序排列较低的组织的用户将在正确的用户之前返回.如果不编写一大堆原生SQL,我怎么能用JPA / CriteriaBuilder解决这个问题?
编辑:这是我想要的一个例子.我正在寻找不同的用户.
>用户A有组织,“AAA大楼”和“ZZZ大楼”
>用户B只有“MMM大楼”的组织
>用户C组织“CCC Building”和“VVV Buidling”
>用户D组织“AAA Building”和“MMM Buidling”
我想要用户D,用户A,用户C和用户B,因为用户A的组织的串联按字母顺序低于用户C的组织的串联,这些组织的字母顺序低于用户B的组织.
解决方法:
您无法为实体编写此类查询.如果您使用的是原生SQL,那么user.id可以组织GROUP BY组织名称,但这不是您想要的.
您只需获取加入用户和组织:
final CriteriaBuilder builder = m_entityManager.getCriteriaBuilder();
final CriteriaQuery criteria = builder.createQuery(User.class);
Root root = criteria.from(User.class);
Fetch organizations = root.fetch("organizations");
criteria.select(c);
TypedQuery query = em.createQuery(criteria);
List users = query.getResultList();
并在内存中对它们进行排序:
Collections.sort(users, new Comparator() {
@Override
public int compare(User user1, User user2) {
SortedSet organizations1 = user1.getOrganizations();
SortedSet organizations2 = user2.getOrganizations();
if(organizations1.isEmpty()) {
if(organizations2.isEmpty()) {
return 0;
} else {
return -1;
}
} else {
if(organizations2.isEmpty()) {
return 1;
} else {
Organization o1 = organizations1.first();
Organization o2 = organizations2.first();
return o1.compareTo(o2);
}
}
}
});
更新
如果您不想在内存中获取所有内容以进行排序,那么我认为仅使用JPQL或Criteria API是不可能的.
假设组织名称是VARCHAR(50),我们首先需要使用正确的填充,然后我们需要首先运行group_concat本机查询:
PostgrSql
SELECT o.user_id,
string_agg(RPAD(o.name, 50) ORDER BY o.name) as ordr
FROM Organization o
GROUP BY o.user_id
order by ordr
MySQL的
SELECT o.user_id,
group_concat(RPAD(o.name, 50) ORDER BY o.name) as ordr
FROM Organization o
GROUP BY o.user_id
order by ordr
对user_id进行排序后,您只需将user_ids提取到List< Long>即可.然后运行第二个JPQL查询来获取用户:
List userIds = ...;
TypedQuery q = em.createQuery(
"select u " +
"from User u " +
"where u.id in :userIds "
, User.class);
q.setParameter("userIds", userIds);
List users = q.getResultList();
标签:java,sorting,orm,jpa,hibernate
来源: https://codeday.me/bug/20190609/1206291.html