简体   繁体   English

查询 JPA 规范中的连接表

[英]Querying a joinned table in JPA Specifications

I want to make a request to the endpoint /users?numberOfBooksGreatherThan=5 , i want the result to be a list of users with more than 5 books each.我想向端点/users?numberOfBooksGreatherThan=5发出请求,我希望结果是每个用户拥有超过 5 本书的列表。 I use the specification API to implements it.我使用规范 API 来实现它。

This is what i tried:这是我试过的:

public static Specification<User> userNumberOfBooksGreaterThan(Long number){
    return ((root, query, criteriaBuilder) -> {
        Join<User, Book> userBooks = root.join("userBooksList");
        return criteriaBuilder.greaterThan(criteriaBuilder.count(userBooks.get("owner")), number);
    });
}

But i got this error但我得到了这个错误

org.postgresql.util.PSQLException: ERROR: aggregate functions are not allowed in WHERE

This is the SQL query executed behind (from logs):这是后面执行的 SQL 查询(来自日志):

select b1_0.user_id,b1_0.name from users b1_0 join books b2_0 on b1_0.user_id=b2_0.owner_id where count(b2_0.owner_id)>5

i saw some answer to a problem like this but it was just in SQL, saying that i should change where by having but i don't know how to do that with JPA Specification.我看到了一些类似这样的问题的答案,但它只是在 SQL 中,说我应该改变where having但我不知道如何使用 JPA 规范来做到这一点。

when i use the query below (left outer join + group by + having) , it returns the correct result, but i don't know how to transform this query into a jpa specification.当我使用下面的查询时(left outer join + group by + having) ,它返回正确的结果,但我不知道如何将此查询转换为 jpa 规范。

select b1_0.user_id,b1_0.name, from users b1_0 left outer join books b2_0 on b1_0.user_id=b2_0.owner_id group by user_id having count(b2_0.owner_id)>=5;

This is the User entity definition这是用户实体定义

@Entity(name = "users")
public class User {
    @Id
    private Long userId;
    private String name;
    @JsonManagedReference
    @OneToMany(mappedBy = "owner")
    private List<Book> userBooksList;
}

This is the Book entity definition这是 Book 实体定义

@Entity(name = "books")
public class Book {
    @Id
    private Long bookId;
    @ManyToOne
    @JoinColumn(name = "ownerId",referencedColumnName = "userId",nullable = false)
    private User owner;
    private Float price;
}

Thank you for your help谢谢您的帮助

I think you have a typo (Should be greaterThan instead of greatherThan).我认为您有错字(应该是 greaterThan 而不是 greatherThan)。

EDIT: You should reverse the query, instead of Join<Book,User> it should be Join<User,Book>.编辑:您应该反转查询,而不是 Join<Book,User> 它应该是 Join<User,Book>。 owner is a field of User entity, not reachable through Book. owner 是 User 实体的字段,无法通过 Book 访问。

public static Specification<User> userNumberOfBooksGreaterThan(Long number) {
return (root, query, criteriaBuilder) -> {
    Join<User, Book> userBooks = root.join("userBooksList");
    return criteriaBuilder.greaterThan(criteriaBuilder.count(userBooks), number);
};}

Changing the comparison in the criteriaBuilder will give you the correct count of books for each user.更改 criteriaBuilder 中的比较将为您提供每个用户的正确书籍数量。

Greetings!你好!

I'm not sure the SQL statement you are trying to get:我不确定您要获取的 SQL 声明:

select b1_0.user_id, b1_0.name from users b1_0 
 left outer join books b2_0 on b1_0.user_id=b2_0.owner_id 
group by user_id 
having count(b2_0.owner_id)>=5;

is syntactically correct, at least for Oracle it is not.在语法上是正确的,至少对于Oracle它不是。 However there are following options:但是有以下选项:

  1. Having/group by拥有/分组依据
(root, cq, cb) -> {
   Join<User, Book> books = root.join("userBooksList");
   cq.having(cb.greaterThanOrEqualTo(cb.count(books), number));
   cq.groupBy(root);
   return cb.and();
}

or或者

(root, cq, cb) -> {
   Root<Book> bookRoot = cq.from(Book.class);
   cq.having(cb.greaterThanOrEqualTo(cb.count(bookRoot), number));
   cq.groupBy(root);
   return cb.equal(bookRoot.get("owner"), root);
}
  1. correlated subquery (this one produces syntactically correct SQL statement)相关子查询(这个产生语法正确的 SQL 语句)
(root, cq, cb) -> {
   Subquery<Long> subq = cq.subquery(Long.class);
   Root<Book> bookRoot = subq.from(Book.class);
   subq.where(cb.equal(bookRoot.get("owner"), subq.correlate(root)));
   return cb.greaterThanOrEqualTo(subq.select(cb.count(bookRoot)), number);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM