spring jpa设置多个主键遇到的小坑及解决
jpa设置多个主键遇到的坑
由于项目需要,对多个业务表单独另外建立对应的历史版本记录表,为了原业务表数据能原封不动记录到历史版本表,需要建立组合主键,id+历史版本号作为主键唯一约束(rid+historyVersion)。
在实体上需要设置为主键的字段加上注解,@Id,例如:
这样会导致,若是该实体存在父类,那就会启动报错,初始化不了
错误信息:does not define an IdClass。
解决办法
必须要在类声名注入@IdClass(HistoryPK.class)。
实体代码例子如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | package com.southgis.officeHouse.entity; import java.io.Serializable; import javax.persistence.Id; import lombok.Data; import lombok.NoArgsConstructor; /** * * @author Administrator * 组合主键 */ @Data public class HistoryPK implements Serializable { private static final long serialVersionUID = 1L; /* * 主键-RID */ private String rid; /* * 主键-历史版本号,保存格式年份_版本号,例如2018_1 */ private String historyVersion; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | package com.southgis.officeHouse.entity; import java.io.Serializable; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.IdClass; import javax.persistence.Index; import javax.persistence.Table; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; /** * * @author Administrator * 单位基本信息历史版本表 */ @Data @EqualsAndHashCode (callSuper= false ) @NoArgsConstructor @Entity @IdClass (HistoryPK. class ) @Table (name = "UNIT_HISTORY" ,indexes={ @Index (name= "inx_unitHistory_orgid" ,columnList= "ORGID" )}) public class UnitHistory extends UnitBase implements Serializable { private static final long serialVersionUID = -4466904221026481006L; /* * 主键-RID */ @Id @Column (name = "RID" , length = 36 ) private String rid; /* * 主键-历史版本号,保存格式年份_版本号,例如2018_1 */ @Id @Column (name = "HISTORY_VERSION" ,length= 36 ) private String historyVersion; } |
jpa遇到多主键表如何进行查询
数据表是原始就存在的,里面存在两个主键:
当建好实体类,然后用jpa去关联操作查询,(根据StudyId)去进行查询的时候,发现原本可以有八条不一样的记录,只是StudyId相同,其他的不同,这个时候,出来确实是八条,但是居然每一条都一样,是根据StudyId一样的数据记录里的都一条。
即当根据StudyId='194205'去查的时候,JPA都会返回八条一样的记录
JPA代码:
1 2 | @Query (value = "select * from tbl_ic_film_info where StudyId = ?1" ,nativeQuery = true ) List<IcFilmInfo> findByStudyIdSQL(String studyId); |
service代码:
然后循环打印icFilmInfoList
FileName查出来都是1
后来才发现是联合主键惹得锅,数据库表中有两个主键,一个是StudyId,还有一个是FileName。
我的实体类是这么定义的(因为我只需要StudyId和FileName的信息就行了):
当JPA在根据StudyId去查询的时候,只会将StudyId当做主键,当StudyId一样的时候,JPA会当做所有的都是同一条记录,不会管FileName是否相同了,一股脑的返回八条一样的数据。
对此其实有很多种解决办法,说下我使用的几种:
1、使用 List<Map<String, Object>>的方式去接收
由于这边数据库的记录值都字符串类型,我就直接使用List<Map<String, String>>了~
JPA代码:
1 2 | @Query (value = "select StudyId,FileName from tbl_ic_film_info where StudyId = ?1" ,nativeQuery = true ) List<Map<String,String>> findByStudyIdMap(String studyId); |
循环答应查询结果:
这种方式有点就是代码简单,但是如果要对查询的结果再进行一步处理的话,就会变的更复杂,不好处理。
2、自定义接收类
新建一个IcFilmInfoVO类:
1 2 3 4 5 6 7 8 9 | @AllArgsConstructor @Data public class IcFilmInfoVO { private String studyId; /** * 文件名 */ private String fileName; } |
注意添加的全参构造方法注解@AllArgsConstructor
JAP代码
1 2 | @Query (value = "select new cloud.image.vo.IcFilmInfoVO(t.studyId,t.fileName) from IcFilmInfo t where t.studyId = ?1" ) List<IcFilmInfoVO> findByStudyId(String studyId); |
注意,这个时候这里的@Query注解里面是没有加nativeQuery = true的
然后循环打印查询结果:
这样即使以后要操作查询的结果也很方便,同时这种自定义接收类的用法还可以用于统计等业务场景,可以接收sum,count等SQL内置函数查询出来的结果。
3、配置联合主键
由于表中是两个主键的存在,接下来改造一下我们的实体类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | @Entity @Data @IdClass (IcFilmInfoPk. class ) @Table (name = "tbl_ic_film_info" ) public class IcFilmInfo implements Serializable { private static final long serialVersionUID = 9121531612760132363L; @Id @Column (name = "StudyId" ) private String studyId; /** * 文件名 */ @Id @Column (name = "FileName" ) private String fileName; } |
在两个主键映射的字段上都标注@Id注解
同时新建一个IcFilmInfoPk类:
1 2 3 4 5 6 | @Data public class IcFilmInfoPk implements Serializable { private static final long serialVersionUID = -1570834456846579284L; private String studyId; private String fileName; } |
在实体类上加上@IdClass(IcFilmInfoPk.class)注解,这个时候就可以用一下JPA代码直接去查询了
1 2 | @Query (value = "select * from tbl_ic_film_info where StudyId = ?1" ,nativeQuery = true ) List<IcFilmInfo> findByStudyIdSQL(String studyId); |
总结:针对上面三种方法,貌似都可以解决我们的问题,但是个人只推荐第三种,应为第三种是最贴合数据库的,使用了联合主键的注解,数据库中也是多主键,但是第二种方式可以很好的解决我们在使用JPA去查询的时候接口其他非数据库字段的信息,例如统计等方面。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
微信公众号搜索 “ 脚本之家 ” ,选择关注
程序猿的那些事、送书等活动等着你
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权/违法违规/事实不符,请将相关资料发送至 reterry123@163.com 进行投诉反馈,一经查实,立即处理!
相关文章
详细分析Java并发集合ArrayBlockingQueue的用法
这篇文章主要介绍了详细分析Java并发集合ArrayBlockingQueue的用法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧2018-04-04解决Hmily与Feign冲突报错 NullPointerException的问题
这篇文章主要介绍了解决Hmily与Feign冲突报错 NullPointerException的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教2021-11-11Map按单个或多个Value排序当Value相同时按Key排序
Map可以先按照value进行排序,然后按照key进行排序。 或者先按照key进行排序,然后按照value进行排序,这样操作都行,这篇文章主要介绍了Map按单个或多个Value排序,当Value相同时按Key排序,需要的朋友可以参考下2023-02-02Spring Cloud Eureka服务注册中心入门流程分析
这篇文章主要介绍了Spring Cloud Eureka服务注册中心入门流程分析,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下2022-06-06
最新评论