【问题标题】:How replace native order by clause on JPA equivalent?如何在 JPA 等效项上替换本地 order by 子句?
【发布时间】:2016-07-05 20:13:30
【问题描述】:

我使用 JPA 2.0 标准生成器。我需要从一个表中获取数据并按列对它们进行排序。此表具有 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;
    ...
        }

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

我用子查询编写本机查询,但它有问题,因为子查询在 JPA 2.0 中的 order 子句和 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 子句?

谢谢!

【问题讨论】:

  • 俱乐部是否有可能拥有许多地址并以不确定的方式排列?否则,您的 JPA 提供程序可能允许您在 from 子句中使用子查询,就像一个表一样。但是,如果您修改查询以提供您想要的内容可能会更好 - 大概是按地址排序的不同全名。类似于“从俱乐部 c 中选择 c.full_name 加入 c.addresses a where a.type =1 order by a.full_address”
  • 感谢您的回答。一个俱乐部可以包含多个类型为 1 的地址,因此在使用 join 时会出现俱乐部的重复。我需要获取所有俱乐部(如果存在类型为 1 或否的地址)并对其进行排序。
  • 添加一个不同的关键字,但如果类型 1 不是唯一的,我不太明白如何使用子查询对非唯一地址进行排序。

标签: jpa subquery one-to-many


【解决方案1】:

这个原生查询也解决了问题,它可以用 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);

【讨论】:

    【解决方案2】:

    它不是非常优雅,但它可以完成工作......

    让您的“俱乐部”类实现 Comparable。将 order-by 逻辑放入 Comparable。然后使用 Collections.sort(unsortedList) 将列表变为排序形式。还有一个 Collections.sort(unsortedList, Comparable) 方法可能很有用,特别是如果您正在执行一堆仅在 order-by 上有所不同的类似方法。

    【讨论】:

      猜你喜欢
      • 2013-08-30
      • 2014-01-17
      • 1970-01-01
      • 2021-12-13
      • 2014-01-12
      • 1970-01-01
      • 1970-01-01
      • 2018-03-23
      • 1970-01-01
      相关资源
      最近更新 更多