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

  • 实体类代码:
  • Repository代码:
  • java代码:
  • 表数据:
  • 遇到的问题:
  • @Id不能乱用,对应的列若有重复,查询到的数据会一直是第一条:
  • 使用联合主键完美解决
  • 使用注解@IdClass绑定复合主键类


最近用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 );

表数据:

postgree 联合主键 jpa联合主键查询_联合主键

遇到的问题:

我首先用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,就到这,下班跑步去。