【问题标题】:JPA criteria: order by child field gives errorJPA 标准:按子字段排序给出错误
【发布时间】:2021-04-25 02:24:02
【问题描述】:

我有 3 个实体。 客户流程文档

一个客户有很多流程,一个流程有很多文档。

我想按文档的updateDate 对客户进行排序。

我的实体如下所示;

客户-

@Entity
public class Customer {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @OneToMany(mappedBy = "customer", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    private List<Process> processes = new ArrayList<>();

    // getter, setter etc.

}

流程-

@Entity
public class Process {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String type;

    @ManyToOne(fetch = FetchType.LAZY)
    private Customer customer;

    @OneToMany(mappedBy = "process", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    private List<Document> documents = new ArrayList<>();

    //getter, setter etc.

}

文档-

@Entity
public class Document {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String note;

    private LocalDateTime updateDate;

    @ManyToOne(fetch = FetchType.LAZY)
    private Process process;

}

我尝试了以下规范-

  public static Specification<Customer> orderByDocumentUploadDate() {
        return (root, query, criteriaBuilder) -> {
            ListJoin<Customer, Process> processJoin = root.join(Customer_.processes);
            ListJoin<Process, Document> documentJoin = processJoin.join(Process_.documents);

            query.orderBy(criteriaBuilder.desc(documentJoin.get(Document_.updateDate)));
            query.distinct(true);
            return null;
        };
    }

它给出了以下错误-

错误:对于 SELECT DISTINCT,ORDER BY 表达式必须出现在选择中 列表

生成的 SQL-

    select distinct customer0_.id   as id1_0_,
                customer0_.name as name2_0_
from customer customer0_
         inner join
     process processes1_ on customer0_.id = processes1_.customer_id
         inner join
     document documents2_ on processes1_.id = documents2_.process_id
order by documents2_.update_date desc
limit ?

我也尝试过分组,如下所示-

    public static Specification<Customer> orderByDocumentUploadDate() {
    return (root, query, criteriaBuilder) -> {
        ListJoin<Customer, Process> processJoin = root.join(Customer_.processes);
        ListJoin<Process, Document> documentJoin = processJoin.join(Process_.documents);

        query.orderBy(criteriaBuilder.desc(documentJoin.get(Document_.updateDate)));
        query.groupBy(root.get(Customer_.id));
        return null;
    };
}

然后它给出了一个不同的错误-

错误:列“documents2_.update_date”必须出现在 GROUP BY 子句或在聚合函数中使用

生成的 SQL-

    select
    customer0_.id as id1_0_,
    customer0_.name as name2_0_ 
from
    customer customer0_ 
inner join
    process processes1_ 
        on customer0_.id=processes1_.customer_id 
inner join
    document documents2_ 
        on processes1_.id=documents2_.process_id 
group by
    customer0_.id 
order by
    documents2_.update_date desc limit ?

我可以通过下面的 sql 来完成; max()在下面的sql中解决了-

    select  customer.* from customer
inner join process p on customer.id = p.customer_id
inner join document d on p.id = d.process_id
group by customer.id
order by max(d.update_date);

但我不能这样做,使用 criteria API。

你有什么建议吗?

【问题讨论】:

    标签: java spring jpa spring-data-jpa jpa-criteria


    【解决方案1】:

    这是一个概念上的误解。

    • 首先,您必须了解内部连接的工作原理。这部分在这种情况下是可以的:[join process table with document table based on document.process_id = process.id]

    • 其次,需要根据文档的更新日期对客户进行排序

    很遗憾,您在这里使用了group byGROUP BY 只返回 grouped by 所在的列。在这种情况下,它将只返回customer_id

    您可以对分组数据使用聚合函数,例如 count()sum() 等。

    当你尝试访问update_date时,会抛出以下错误:

    ERROR: column "documents2_.update_date" must appear in the GROUP BY clause or be used in an aggregate function
    

    现在,我们怎样才能摆脱它?

    • 所以首先我们需要做join 来获取客户ID。得到客户id后,我们应该按照客户id对数据进行分组,然后使用max()来获取每个组的max_date(如果需要,然后是最小值)
    SELECT 
       customer_id,
       max(date) AS max_date
    FROM    
       document 
       JOIN process ON process.id = document.process_id
    GROUP BY customer_id
    

    它将返回一个临时表,如下所示:

    customer_id max_date
    1 2020-10-24
    2 2021-03-15
    3 2020-09-24
    4 2020-03-15

    使用临时表,您现在可以按日期对customer_id 进行排序

    SELECT
        customer_id,
        max_date
    FROM    
        (SELECT 
            customer_id,
            max(date) AS max_date
        FROM    
            document 
            JOIN process ON process.id = document.process_id
        GROUP BY customer_id) AS pd
    ORDER BY max_date DESC
    

    希望这会有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-01-10
      • 1970-01-01
      • 2017-06-27
      • 1970-01-01
      • 2017-11-04
      • 2021-07-02
      • 2016-09-28
      • 2020-06-17
      相关资源
      最近更新 更多