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 );
表数据:
遇到的问题:
我首先用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,就到这,下班跑步去。