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