简体   繁体   English

Hibernate / SQL:仅在存在一对多关系时选择记录,否则返回太多

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

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. 在我的应用程序中,我有2个表,“结算结果”和“结算状态”结算结果包含一些基本数据,例如名称,类型等。SettlementState是与“结算结果”相关的“很多”方面,由“结算结果PK”和“状态为多对”组成-一个ID作为PK和一个日期。 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. 现在,我希望使用HQL /普通SQL选择“结算结果”中的行,例如具有状态ID == 3的行,但没有任何具有较高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". 当我们创建SettlementResult时,总会有一些“工作流程”。 Firstly, Result has status Created (ID 1). 首先,结果的状态为已创建(ID 1)。 Then it can be Rejected(ID 4) or Confirmed (ID 2). 然后可以将其拒绝(ID 4)或确认(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). 因此,一个SettlementResult可以具有状态ID为1,2,4(已创建,已确认但未接受=已拒绝)的SettlementStates。

The problem is, that I want to select only those SettlementResults which have certain status (for examle Created)." 问题是,我只想选择具有某些状态(例如创建的示例)的SettlementResults。”

With HQL query like this: 使用这样的HQL查询:

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). 它返回每个结算结果,甚至包括状态为1,2,3的结算结果(原因是集合包含ID等于创建的ID)。

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. 是否可以仅选择那些仅具有某些状态的结算结果,例如,如果我们想要Created [ID 1],则只能获得所有结算状态为1的状态,而没有2,3或4状态。 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] ? 当我们选择状态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;
}

You have two options here: 您在这里有两个选择:

If you see your query you are fetching SettlementResult objects 如果看到查询,则正在获取SettlementResult对象

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

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 PK (This is what you have observed as well). 您的查询是完美的,但是一旦拥有父对象SettlementResult并访问OneToMany集合沉降状态,hibernate将根据SettlementResult PK加载所有这些状态(这也是您观察到的)。

So Option-1 : Go through Child to Parent This means return SettlementState objects from your query as: 因此, 选项1从子级转到父级这意味着从查询中返回SettlementState对象,如下所示:

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

And then you can access SettlementResult from state object, because you have defined ManyToOne for SettlementResult in SettlementState class. 然后,您可以从状态对象访问SettlementResult,因为您已经在SettlementState类中为SettlementResult定义了ManyToOne。 In this case you will definitely have those SettlementResult objects what you are looking for. 在这种情况下,您肯定会找到所需的SettlementResult对象。

Option-2: Divide your SettlementState objects Option 1 will work for you but this solution might seem odd to you. 选项2:划分您的SettlementState对象选项1将为您工作,但此解决方案对您来说似乎很奇怪。 So the best way to resolve this problem is you can divide Settlement State objects (as described in your problem) 因此,解决此问题的最佳方法是您可以划分“结算状态”对象(如问题中所述)

1. RejectedSettlementState
2. NonRejectedSettlementState

These two classes will extend one base abstract class (SettlementState). 这两个类将扩展一个基本抽象类(SettlementState)。 You can define discriminator formula on status id. 您可以在状态ID上定义鉴别器公式。 Once you have these classes then you can associate these subclasses into SettlementResult. 一旦有了这些类,就可以将这些子类关联到SettlementResult中。 Here are classes you need (sudo) 这是您需要的课程(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
}

Now the SettlementResult class 现在是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;

}

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. 您只需加载父对象SettlementResult,然后访问您已拒绝或未拒绝的结算状态。 Hibernate will use formula condition to initialize these collections using lazy load as defined in SettlementResult class. Hibernate将使用公式条件通过SettlementResult类中定义的延迟加载来初始化这些集合。

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! 祝好运!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM