首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Hibernate/SQL:仅当存在于一对多关系中时才选择记录,返回太多

Hibernate/SQL:仅当存在于一对多关系中时才选择记录,返回太多
EN

Stack Overflow用户
提问于 2012-12-13 17:35:06
回答 1查看 3.2K关注 0票数 0

在我的应用中,我有两个表,结算结果和结算状态结算结果包含一些基本数据,如名称、类型等。SettlementState是与结算结果关系的“多”面,由结算结果主键和状态组成,如主键和日期一样多对一的ID。示例数据:

代码语言:javascript
复制
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/Plain SQL从结算结果中选择具有例如状态ID == 3的行,而不是具有更高Id的行。

有几种可能的状态:

代码语言:javascript
复制
Status ID | Desc
-----------------
1 | Created
2 | Confirmed
3 | Accepted
4 | Rejected

当我们创建SettlementResult时,总会有一些“工作流程”。首先,Result的状态为Created (ID 1)。然后可以拒绝(ID 4)或确认(ID 2)。然后再一次,我们可以接受或拒绝。

因此,一个SettlementResult可以具有状态ID为1、2、4的SettlementStates (已创建、已确认,但不是Accepted=Rejected)。

问题是,我只想选择那些具有特定状态(对于examle Created)的SettlementResults。“

HQL查询如下:

代码语言:javascript
复制
Query query = session.createSQLQuery( "select distinct s from SettlementResult s join s.settlementStates states where states.settlementStatePK.status.statusId == 1" );

返回所有结算结果,包括状态为1、2、3的结算结果(原因集合中包含ID为created的结算结果)。

可以只选择那些只具有特定状态的结算结果吗?例如,如果我们想要CreatedID 1,我们只会得到状态为1的所有结算结果,而没有2,3或4状态。当我们选择那些状态id为3的,我们可以接受,如果它有状态id = 1,2,3但不是4的结算状态。某种max[status.id]

代码语言:javascript
复制
@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;
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2012-12-17 02:47:18

这里有两个选项:

如果您看到您的查询,那么您正在获取SettlementResult对象

代码语言:javascript
复制
Query query = session.createSQLQuery( "select distinct s from SettlementResult s join s.settlementStates states where states.settlementStatePK.status.statusId == 1" );

你的查询是完美的,但是一旦你有了父对象SettlementResult并且你访问了OneToMany集合settlementStates,hibernate就会在SettlementResult P.K.的基础上加载所有它们(这也是你已经观察到的)。

所以-1\f25-1\f6选项-1\f25-1\f25-1\f6从子-1\f6到-1\f25 Parent -1\f6这意味着从查询中返回SettlementState对象为:

代码语言:javascript
复制
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: Divide your SettlementState objects选项1适合您,但是这个解决方案对您来说可能有点奇怪。因此,解决此问题的最好方法是您可以划分结算状态对象(如您的问题中所述)

代码语言:javascript
复制
1. RejectedSettlementState
2. NonRejectedSettlementState

这两个类将扩展一个基础抽象类(SettlementState)。您可以在状态id上定义鉴别器公式。一旦拥有了这些类,就可以将这些子类关联到SettlementResult中。以下是您需要的类(sudo)

代码语言:javascript
复制
@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类

代码语言:javascript
复制
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类中定义的延迟加载来初始化这些集合。

备注对我来说,这两种解决方案都是可以接受的,这取决于您希望在系统中使用哪种解决方案。第二种选择让你在未来有更多的优势。

任何更多信息:请询问!我已经尽了最大的努力让你理解这个想法:)。祝你好运!

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/13856898

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档