簡體   English   中英

Hibernate / SQL:僅在存在一對多關系時選擇記錄,否則返回太多

[英]Hibernate/SQL: Selecting records only if exist in one-to-many relationship, returns too many

在我的應用程序中,我有2個表,“結算結果”和“結算狀態”結算結果包含一些基本數據,例如名稱,類型等。SettlementState是與“結算結果”相關的“很多”方面,由“結算結果PK”和“狀態為多對”組成-一個ID作為PK和一個日期。 示例數據:

Settlement Result
------------------------------
ID| Name      | Sth
------------------------------
1 | Some Name | Something more
2 | Name2     | more2

Settlement State
----------
Result's ID | StatusId     | Date 
------------------------------
1           | 1            | some date
1           | 2            | date
1           | 3            | date
2           | 1            | date

現在,我希望使用HQL /普通SQL選擇“結算結果”中的行,例如具有狀態ID == 3的行,但沒有任何具有較高ID的行。

可能的狀態很少:

Status ID | Desc
-----------------
1 | Created
2 | Confirmed
3 | Accepted
4 | Rejected

當我們創建SettlementResult時,總會有一些“工作流程”。 首先,結果的狀態為已創建(ID 1)。 然后可以將其拒絕(ID 4)或確認(ID 2)。 然后我們可以接受或拒絕。

因此,一個SettlementResult可以具有狀態ID為1,2,4(已創建,已確認但未接受=已拒絕)的SettlementStates。

問題是,我只想選擇具有某些狀態(例如創建的示例)的SettlementResults。”

使用這樣的HQL查詢:

Query query = session.createSQLQuery( "select distinct s from SettlementResult s join s.settlementStates states where states.settlementStatePK.status.statusId == 1" );

它返回每個結算結果,甚至包括狀態為1,2,3的結算結果(原因是集合包含ID等於創建的ID)。

是否可以僅選擇那些僅具有某些狀態的結算結果,例如,如果我們想要Created [ID 1],則只能獲得所有結算狀態為1的狀態,而沒有2,3或4狀態。 當我們選擇狀態ID為3的那些時,我們可以接受狀態ID為1,2,3但不是4的結算狀態。某種max[status.id]嗎?

@Entity
@Table(name = "SETTLEMENT_STATE")
public class SettlementState
{
    @EmbeddedId
    private SettlementStatePK settlementStatePK;

    @Column(name = "DESCRIPTION")
    private String description;

    @Column(name = "STATUS_DTTM")
    private Date statusDate;
}

@Embeddable
public class SettlementStatePK implements Serializable
{
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "STATUS_ID")
    private Status status;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "SETTLEMENT_RESULT_ID")
    private SettlementResult settlementResult;
}

@Entity
@Table(name = "SETTLEMENT_RESULT")
public class SettlementResult implements Serializable
{
    @Id
    @Column(name = "SETTLEMENT_RESULT_ID")
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "STATUS_ID")
    private Status status;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "MODEL_GROUP_ID")
    private SettlementModelGroup settlementModelGroup;

    @Column(name = "\"MODE\"")
    private Integer mode;

    @Column(name = "CREATED_DTTM")
    private Date createdDate;

    @Column(name = "DESCRIPTION")
    private String description;

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "settlementStatePK.settlementResult")
    private List<SettlementState> settlementStates;
}

您在這里有兩個選擇:

如果看到查詢,則正在獲取SettlementResult對象

Query query = session.createSQLQuery( "select distinct s from SettlementResult s join s.settlementStates states where states.settlementStatePK.status.statusId == 1" );

您的查詢是完美的,但是一旦擁有父對象SettlementResult並訪問OneToMany集合沉降狀態,hibernate將根據SettlementResult PK加載所有這些狀態(這也是您觀察到的)。

因此, 選項1從子級轉到父級這意味着從查詢中返回SettlementState對象,如下所示:

Query query = session.createSQLQuery( "select distinct states from SettlementResult s join s.settlementStates states where states.settlementStatePK.status.statusId == 1" );

然后,您可以從狀態對象訪問SettlementResult,因為您已經在SettlementState類中為SettlementResult定義了ManyToOne。 在這種情況下,您肯定會找到所需的SettlementResult對象。

選項2:划分您的SettlementState對象選項1將為您工作,但此解決方案對您來說似乎很奇怪。 因此,解決此問題的最佳方法是您可以划分“結算狀態”對象(如問題中所述)

1. RejectedSettlementState
2. NonRejectedSettlementState

這兩個類將擴展一個基本抽象類(SettlementState)。 您可以在狀態ID上定義鑒別器公式。 一旦有了這些類,就可以將這些子類關聯到SettlementResult中。 這是您需要的課程(sudo)

@DiscriminatorForumla("case when status_id == 4 then "REJECTEDSTATE" else "NONREJECTEDSTATE" end")
public abstract class SettlementState{
...
// Define all of your common fields in this parent class
}

@DiscriminatorValue("REJECTEDSTATE")
public class RejectedSettlementState extends SettlementState{
...
// define only fields specific to this rejected state
}


@DiscriminatorValue("NOTREJECTEDSTATE")
public class NonRejectedSettlementState extends SettlementState{
...
// define only fields specific to this non-rejected state
}

現在是SettlementResult類

public class SettlementResult{

@OneToMany(fetch = FetchType.LAZY, mappedBy = "settlementStatePK.settlementResult")
private List<RejectedSettlementState> rejectedSettlementStates;

@OneToMany(fetch = FetchType.LAZY, mappedBy = "settlementStatePK.settlementResult")
private List<NonRejectedSettlementState> nonRejectedSettlementStates;

}

所以一旦有了所有這些對象。 然后,您不需要查詢狀態。 您只需加載父對象SettlementResult,然后訪問您已拒絕或未拒絕的結算狀態。 Hibernate將使用公式條件通過SettlementResult類中定義的延遲加載來初始化這些集合。

注意對我來說,兩種解決方案都是可以接受的,這取決於您希望系統中的哪一種解決方案。 第二種選擇為您提供了更多的未來優勢。

任何更多信息:請詢問! 我已盡力讓您理解這個想法:)。 祝好運!

暫無
暫無

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

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