In my app, I have 2 tables, Settlement Result and Settlement State
Settlement Result contains some basic data like name, type etc.
SettlementState is the “many” side of relatioship with Settlement Result and consist of Settlement Result PK and Status as Many-To-One ID as PK and a date. Example data:
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
Now I wish to select with HQL/Plain SQL that rows from Settlement Result, that have for example Status Id == 3, but not any with higher ID.
There are few possible statuses:
Status ID | Desc
-----------------
1 | Created
2 | Confirmed
3 | Accepted
4 | Rejected
When we are creating SettlementResult, there’s always some “workflow”. Firstly, Result has status Created (ID 1). Then it can be Rejected(ID 4) or Confirmed (ID 2). Then again we can Accept it or Reject.
So one SettlementResult can have SettlementStates with Status ID of 1,2,4 (Created, Confirmed, but not Accepted=Rejected).
The problem is, that I want to select only those SettlementResults which have certain status (for examle Created).”
With HQL query like this:
Query query = session.createSQLQuery( "select distinct s from SettlementResult s join s.settlementStates states where states.settlementStatePK.status.statusId == 1" );
It returns every Settlement Result, even those with Statuses 1,2,3 (cause collection contains the one with ID equal to created).
Is it possible to select ONLY those Settlement Results which have ONLY certain status for example if we want Created[ID 1], we get all with Settlement State status of 1 only, without 2,3 or 4 status. When we choose to select those with status id 3, we can accept if it has Settlement State with status id = 1,2,3 but NOT 4. Some kind of 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;
}
You have two options here:
If you see your query you are fetching SettlementResult objects
Your query is perfect but once you have parent object SettlementResult and you access OneToMany collection settlementStates, hibernate will load all of them on the basis of SettlementResult P.K. (This is what you have observed as well).
So Option-1:
Go through Child to Parent
This means return SettlementState objects from your query as:
And then you can access SettlementResult from state object, because you have defined ManyToOne for SettlementResult in SettlementState class. In this case you will definitely have those SettlementResult objects what you are looking for.
Option-2: Divide your SettlementState objects
Option 1 will work for you but this solution might seem odd to you. So the best way to resolve this problem is you can divide Settlement State objects (as described in your problem)
These two classes will extend one base abstract class (SettlementState). You can define discriminator formula on status id. Once you have these classes then you can associate these subclasses into SettlementResult. Here are classes you need (sudo)
Now the SettlementResult class
So once you have all these objects. Then you don’t need query on status. You simply load the parent object SettlementResult and then access your rejected or non-rejected settlement states. Hibernate will use formula condition to initialize these collections using lazy load as defined in SettlementResult class.
Note
Both solutions to me are acceptable, it depends which one you will like in your system to be there. Second option gives you more edges for future.
Any more info: please ask! I have tried my best to get you through this idea :). Good Luck!