如何在 JPA 等效项上按子句替换本机顺序?

How replace native order by clause on JPA equivalent?

我使用 JPA 2.0 条件生成器。我需要从一个 table 中获取数据并从另一个中按列对它们进行排序。这 table 具有 OneToMany 关系:

 class Club{
   @OneToMany(mappedBy = "club")
    private List<Address> addresses;
    ...
    }

class Address{
@JoinColumn(name = "club_id", referencedColumnName = "id")
@ManyToOne(fetch = FetchType.LAZY)
private Club club;

@Column(name = "type")
private Long type;

@Column(name = "full_address")
    private String full_address;
    ...
        }

可能是某种类型的多个地址,但我只需要这一特定地址的一行。

我用子查询编写本机查询,但它有问题,因为子查询不使用 in order 子句和 JPA 2.0 中的 select 子句。

select c.full_name from club c
  ORDER BY (select a.full_address from address a WHERE c.id= a.club_id and a.type=1 LIMIT 1)


select c.full_name, (select a.full_address from address a WHERE a.type=1 AND c.id=a.club_id LIMIT 1) as full_address FROM club c
ORDER BY fullAddress;

如何在 JPA 等效项上替换本机 order by 子句?

谢谢!

它不是很优雅,但它完成了工作...

使您的 "Club" class 实现具有可比性。将 order-by 逻辑放入 Comparable 中。然后使用 Collections.sort(unsortedList) 将列表转换为排序形式。还有一个 Collections.sort(unsortedList, Comparable) 方法可能很有用,特别是如果你正在做一堆类似的方法,只是顺序不同。

这个本机查询也解决了问题,它可以用 JPA 查询代替

select c.full_name, min(a.full_address) FROM club c LEFT JOIN address a on c.id = a.club_id
where a.id is null or a.type=1 or not exists(SELECT  1 from address aSub WHERE aSub .club_id=c.id AND aSub.type=1)
GROUP BY  c.id, c.full_name ORDER BY min(a.full_address);

等效于 JPA

 CriteriaBuilder builder = em.getCriteriaBuilder();
        CriteriaQuery<ClubItem> query = builder.createQuery(ClubItem.class);

    Root<Club> root = query.from(Club.class);
    Join<Club, Address> addressJoin = root.join(Club_.address, JoinType.LEFT);

query.select(builder.construct(ClubItem.class, root.get(Club_.id), root.get(Club_.fullName), builder.function("min", String.class, addressJoin.get(Address_.fullAddress))));

    Subquery<Address> subquery = query.subquery(Address.class);
    Root<Address> addressRoot = subquery.from(Address.class);

    subquery.select(addressRoot);
    subquery.where(
            builder.and(
                    builder.equal(addressRoot.get(Address_.type), 1),
                    builder.equal(addressRoot.get(Address_.clubId), root.get(Club_.id))));   

    query.where(builder.or(builder.isNull(addressJoin), builder.equal(addressJoin.get(Address_.type), builder.literal(new Long(1))),
            builder.not(builder.exists(subquery))));

    query.groupBy(root.get(Club_.id), root.get(Club_.fullName))

            Order order = builder.asc(builder.function("min", String.class, addressJoin.get(Address_.fullAddress)));

            query.orderBy(order);            

    TypedQuery<ClubItem> contentQuery = em.createQuery(query);