簡體   English   中英

如何將from-subquery轉換為Hibernate Criteria語句

[英]How can i convert a from-subquery into a Hibernate Criteria statement

模型

我有以下三個類的模型。 A類包含1個B,可以包含0個或更多個C. B類和C類都包含我想在A范圍內總結的金額。

class TableA {
    @Id
    Id id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "table_b_id", nullable = false)
    TableB tableB;

    @OneToMany(mappedBy = "tableA", fetch = FetchType.LAZY)
    Set<TableC> tableCs;
}

class TableB {
    @Id
    Id id;

    @Column(name = "amount_b")
    Long amountB;
}

class TableC {
    @Id
    Id id;

    @Column(name = "amount_c", nullable = false)
    Long amountC;

    @JoinColumn(name = "table_a_id")
    TableA tableA;
}

我的任務是計算兩個值“sum(c.amount)+ b.amount”的組成,並查看它們是否在定義的最小/最大間隔內,例如[0,100]。 結果是符合此條件的A列表。 我被要求只在Hibernate Criteria中執行此操作。

為此,我構建了一個表達此要求的SQL語句:

select compositeSum from 
(SELECT sum(tableC.amountC) + tableB.amountB as 'compositeSum'
FROM tableA A
left join tableB B on A.b_id = B.id
left join tableC C on C.a_id = A.id) SUBQUERY
where compositeSum between 0 and 100;

嘗試

由於存在聚合函數“sum()”以及算術運算“+”,我嘗試使用子查詢來解決問題。 我得到的最接近的是以下解決方案:

Long min = 0l;
Long max = 100l;

DetachedCriteria subquery = DetachedCriteria.forClass(TableA.class, "inner")
                .createAlias("tableC", "tableC", JoinType.LEFT_OUTER_JOIN)
                .createAlias("tableB", "tableB")
                .setProjection(Projections.sqlProjection("coalesce(sum(amountC), 0) + amountB", new String[] {"compositeSum"}, new Type[] {StandardBasicTypes.LONG}));

Criteria criteria = session().createCriteria(TableA.class, "outer")
                .add(Subqueries.ge(max, subquery))
                .add(Subqueries.le(min, subquery));

問題

問題是這會轉換為where子句中使用的子查詢。

select * from A this_ 
where ? >= 
(select sum(amountC) + amountB from table_A tableA_ 
inner join table_B tableB2_ on tableA_.table_b_id=tableB2_.id 
inner join table_C tableC1_ on tableA_.id=tableC1_.table_a_id) 
and ? <= 
(select sum(amountC) + amountB from table_A tableA_ 
inner join tableB tableB2_ on tableA_.table_B_id=tableB2_.id 
inner join table_C tableC1_ on tableA_.id=tableC1_.table_a_id)

我想構建一個子查詢,可以將其提供給主查詢的from子句。 相反,我有一個子查詢被送到where子句。 這不是我想要的,並導致奇怪的結果。

有誰知道是否有可能將子查詢提供給Hibernate Criteria中的from-clause? 非常感謝!

(更新)

顯然,在內部查詢中添加一個指向外部查詢的附加過濾器可以解決問題。 要從子查詢引用父查詢實體,請使用magic關鍵字“this”。

Long min = 0l;
Long max = 100l;

DetachedCriteria subquery = DetachedCriteria.forClass(TableA.class, "inner")
                .createAlias("tableC", "tableC", JoinType.LEFT_OUTER_JOIN)
                .createAlias("tableB", "tableB")
                .setProjection(Projections.sqlProjection("coalesce(sum(amountC), 0) + amountB", new String[] {"compositeSum"}, new Type[] {StandardBasicTypes.LONG}))
                .add(Restrictions.eqProperty("id", "this.id"));

Criteria criteria = session().createCriteria(TableA.class, "outer")
                .setProjection(Projections.property("id"))
                .add(Subqueries.ge(max, subquery))
                .add(Subqueries.le(min, subquery));

添加額外過濾器背后的邏輯是min / max是標量,並且您希望子查詢返回另一個標量而不是列表來進行比較,否則會導致不穩定的行為。

然后它變成一個相關的子查詢:

select * from A this_ 
where ? >= 
(select sum(amountC) + amountB from table_A tableA_ 
inner join table_B tableB2_ on tableA_.table_b_id=tableB2_.id 
inner join table_C tableC1_ on tableA_.id=tableC1_.table_a_id 
where tableA_.id = this_.id) 
and ? <= 
(select sum(amountC) + amountB from table_A tableA_ 
inner join tableB tableB2_ on tableA_.table_B_id=tableB2_.id 
inner join table_C tableC1_ on tableA_.id=tableC1_.table_a_id
where tableA_.id = this_.id)

這個解決方案是一種不同類型的子查詢,並且可能會慢一點,因為您執行子查詢兩次,但它完成了這項工作。

有子句

請注意,使用having子句也可以使用SQL解決方案。 在下面,您可以找到上述轉換為having-clause。 唯一的問題是Hibernate Criteria 不支持 having-clauses。

SELECT coalesce(sum(amountC),0) + amountB as 'compositeSum'
FROM table_A tableA
left join table_B tableB on tableA.table_b_id = tableB.id
left join table_C tableC on tableC.table_a_id = tableA.id

group by m.id
having compositeSum between 0 and 100

您不需要子查詢。 簡化您的查詢,如下所示:

SELECT sum(tableC.amountC) + tableB.amountB as 'compositeSum'
FROM tableA A
left join tableB B on A.b_id = B.id
left join tableC C on C.a_id = A.id
where (sum(tableC.amountC) + tableB.amountB) between 0 and 100;

現在改變你的hibernate代碼。

顯然,在內部查詢中添加一個指向外部查詢的附加過濾器可以解決問題。 要從子查詢引用父查詢實體,請使用magic關鍵字“this”。

Long min = 0l;
Long max = 100l;

DetachedCriteria subquery = DetachedCriteria.forClass(TableA.class, "inner")
                .createAlias("tableC", "tableC", JoinType.LEFT_OUTER_JOIN)
                .createAlias("tableB", "tableB")
                .setProjection(Projections.sqlProjection("coalesce(sum(amountC), 0) + amountB", new String[] {"compositeSum"}, new Type[] {StandardBasicTypes.LONG}))
                .add(Restrictions.eqProperty("id", "this.id"));

Criteria criteria = session().createCriteria(TableA.class, "outer")
                .setProjection(Projections.property("id"))
                .add(Subqueries.ge(max, subquery))
                .add(Subqueries.le(min, subquery));

添加額外過濾器背后的邏輯是min / max是標量,並且您希望子查詢返回另一個標量而不是列表來進行比較,否則會導致不穩定的行為。

然后它變成一個相關的子查詢:

select * from A this_ 
where ? >= 
(select sum(amountC) + amountB from table_A tableA_ 
inner join table_B tableB2_ on tableA_.table_b_id=tableB2_.id 
inner join table_C tableC1_ on tableA_.id=tableC1_.table_a_id 
where tableA_.id = this_.id) 
and ? <= 
(select sum(amountC) + amountB from table_A tableA_ 
inner join tableB tableB2_ on tableA_.table_B_id=tableB2_.id 
inner join table_C tableC1_ on tableA_.id=tableC1_.table_a_id
where tableA_.id = this_.id)

有子句

請注意,使用having子句也可以使用SQL解決方案。 在下面,您可以找到上述轉換為having-clause。 唯一的問題是Hibernate Criteria 不支持 having-clauses。

SELECT coalesce(sum(amountC),0) + amountB as 'compositeSum'
FROM table_A tableA
left join table_B tableB on tableA.table_b_id = tableB.id
left join table_C tableC on tableC.table_a_id = tableA.id

group by m.id
having compositeSum between 0 and 100

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM