JPA里查询实体类因@Id导致的数据重复及使用联合主键的解决方法

最近用JPA写代码写得比较爽,感觉比mybatis方便多了,但是毕竟JPA是从hibernate上封装的,功能有点强大,也有点不好上手,今天就因为主键而翻车。记录在此希望小伙伴们能避免犯同样的错。

实体类代码:

package wysghmbb.today.jiaban.ing;

import lombok.Data;

import javax.persistence.*;
import java.io.Serializable;

@Data
@Entity
@Table(name = "s_procedure_set")
public class ProcedureSet implements Serializable {

    //流程模板id
    @Id
    @Column
    private Integer settingProcedureTypeId;

    //流程模板名称
    @Column
    private String settingProcedureTypeName;

    //流程模板步骤id
    @Column
    private Integer settingStepId;

    //同意-下一步骤id
    @Column
    private Integer settingNextYesStepId;

    //驳回-下一步骤id
    @Column
    private Integer settingNextNoStepId;

    //流程模板步骤组件id
    @Column
    private Integer settingComponentId;


}

实体类里有几个属性名取得很丑,但却是自己在上一个翻车现场总结出的血泪教训,settingProcedureTypeId至少比比SProcedureTypeId能用,好奇的小伙伴可以看我另一个博客:
《lombok使用@Data注解下的不标准驼峰导致参数获取不到的问题及解决》
链接: link.

Repository代码:

@Repository
public interface ProcedureSetRepository extends JpaRepository<ProcedureSet,Long>, JpaSpecificationExecutor<ProcedureSet> {

    @Query(value = "select s from ProcedureSet s where s.settingProcedureTypeId = ?1 and s.settingStepId = ?2 ")
    ProcedureSet getProcedureSetStep(Integer settingProcedureTypeId,Integer sStepId);
    
}    

java代码:

Integer secondStepId = procedureSetFirst.getSettingNextYesStepId();

//获取第二行规则
ProcedureSet procedureSetSecond = procedureSetRepository.getProcedureSetStep(orderMainInfo.getSettingProcedureTypeId(),secondStepId);
            
logger.info( "第二行的规则:"+procedureSetSecond );   

表数据:

在这里插入图片描述

遇到的问题:

我首先用procedureSetRepository.getProcedureSetStep(4,1)方法查询了第一行的规则得到的带红圈的那一行,然后再procedureSetRepository.getProcedureSetStep(4,2),正常会得到带绿圈的那一行,接口仍然是带红圈的那一行。
太诡异了,我甚至写了个NativeQuery=true的语句,查到的仍是带红圈的;

@Id不能乱用,对应的列若有重复,查询到的数据会一直是第一条:

查阅了一些资料才意识到问题出在@Id的使用上,因为我把@Id加到的是settingProcedureTypeId列上,但settingProcedureTypeId并非主键,且在表中有重复数据。
为了测试,我加了个没用的字段id,并在实体类中用@Id注解,终于能查询到带绿圈的数据了。
可是这个方法有点笨,还有更好的方法呢。

使用联合主键完美解决

在我的表中,settingProcedureTypeId和settingStepId应该算是联合主键,我应该用注解将它俩的关系公之于众,这样做:

package haha.yaoxiabanle.qupaobuba;

import lombok.Data;

import javax.persistence.*;
import java.io.Serializable;

@Data
@Entity
@Table(name = "s_procedure_set")
@IdClass(ProcedureSetKey.class)
public class ProcedureSet implements Serializable {

    //流程模板id
    @Id
    @Column
    private Integer settingProcedureTypeId;

    //流程模板名称
    @Column
    private String settingProcedureTypeName;

    //流程模板步骤id
    @Id
    @Column
    private Integer settingStepId;

    //同意-下一步骤id
    @Column
    private Integer settingNextYesStepId;

    //驳回-下一步骤id
    @Column
    private Integer settingNextNoStepId;

    //流程模板步骤组件id
    @Column
    private Integer settingComponentId;


}

class ProcedureSetKey implements Serializable{
    private Integer settingProcedureTypeId;
    private Integer settingStepId;
} 

使用注解@IdClass绑定复合主键类

创建小类ProcedureSetKey,作为复合主键类,用来存放需要生产联合主键的属性,该类需要实现序列化。
使用注解@IdClass(ProcedureSetKey.class)将复合主键类绑定进来。

当然,复合主键类也可以放在单独文件里,我图省事给放一起了。

就这样,我如愿查询到了带绿圈的那一行。以后对于能做联合主键的,在数据库里就约束好,创建实体类的时候也用复合主键类进行绑定,再也不要乱绑@Id的情况。ok,就到这,下班跑步去。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值