如何在 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);
我使用 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);