[英]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.