JPA自定義對象接收查詢結(jié)果集操作
最近使用JPA的時(shí)候,碰到需要自定義查詢結(jié)果集的場景,網(wǎng)上搜了一下,都是需要自定義方法寫一大串代碼實(shí)現(xiàn)的,太繁瑣了,有那時(shí)間還不如用mybaits。
用JPA就是要盡量通過聲明接口解決持久層問題,要不然鬼用。逼得沒辦法去了官網(wǎng)看看文檔,再?zèng)]有就放棄了,沒時(shí)間看源碼。最終找到我想要的結(jié)果了。
例如,傳統(tǒng)的JPA接口實(shí)現(xiàn)如下所示:
class Person {
@Id UUID id;
String firstname, lastname;
Address address;
static class Address {
String zipCode, city, street;
}
}
interface PersonRepository extends Repository<Person, UUID> {
Collection<Person> findByLastname(String lastname);
}
自定義對象接收查詢結(jié)果集方法如下:
(1)增加接收數(shù)據(jù)接口
interface NamesOnly {
String getFirstname();
String getLastname();
}
(2)增加持久層接口
interface PersonRepository extends Repository<Person, UUID> {
Collection<NamesOnly> findByLastname(String lastname);
}
如果要對查詢結(jié)果進(jìn)行序列號的話就會有點(diǎn)問題:
{
"errorCode": "00",
"errorMessage": "操作成功",
"returnObject": [
{
"createtime": 1526358195000,
"id": 49,
"lastupdatetime": 1526358195000,
"status": "2",
"target": {
"createtime": 1526358195000,
"lastupdatetime": 1526358195000,
"check_Wicket": "1",
"facility_name": "血壓測量",
"facility_Num": "C3",
"id": 49,
"status": "2",
"check_name": "小湯154",
"check_Num": "BY185201805140001"
},
"targetClass": "org.springframework.data.jpa.repository.query.AbstractJpaQuery$TupleConverter$TupleBackedMap"
}
]
}
會出現(xiàn)targetClass這個(gè)字段,不能直接把結(jié)果拿來用,很惡心,又不想寫代碼中轉(zhuǎn)下。
經(jīng)過后來的摸索,其實(shí)如果只是為了返回JSON,也可以直接在Repository層直接用List<Map<String,Object>>來返回,
Map<String,Object>對應(yīng)單條查詢結(jié)果,完美解決序列化問題。
完畢。就這么簡單。
補(bǔ)充:SpringBoot JPA查詢結(jié)果映射到自定義實(shí)體類
場景
舉一個(gè)簡單的例子:
比如有一個(gè)Position實(shí)體類
@Entity
@Table(name = "position")
public class Position implements Serializable {
private static final long serialVersionUID = 768016840645708589L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private BigDecimal salary;
private String city;
...//省略getset方法
...//省略toString方法
}
然后有一個(gè)PositionDetail實(shí)體類
@Entity
@Table(name = "position_detail")
public class PositionDetail implements Serializable {
private static final long serialVersionUID = 4556211410083251360L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Long pid;
private String description;
...//省略getset方法
...//省略toString方法
}
需求:
查詢職位基本信息,職位描述,因?yàn)樯婕暗絻蓮埍聿僮?,簡單的查詢并不能滿足我們的需求,因此就需要自定義查詢接口并返回符合需求的結(jié)果。
接下來再定義一個(gè)實(shí)體類,用來接收查詢結(jié)果
public class PositionDO {
private Long id;
private String name;
private BigDecimal salary;
private String city;
private String description;
public PositionDO(Long id, String name, BigDecimal salary, String city, String description) {
this.id = id;
this.name = name;
this.salary = salary;
this.city = city;
this.description = description;
}
...//省略getset方法
...//省略toString方法
}
編寫Dao接口,用來實(shí)現(xiàn)CRUD操作
public interface PositionDao extends JpaRepository<Position, Long> {
@Query(nativeQuery = true, value = "select t1.id, t1.name, t1.salary, t1.city, t2.description) \n" +
"from position t1 left join position_detail t2 on t1.id = t2.pid \n" +
"where t1.id = :id")
PositionDO findPositionById(@Param("id") Long id);
}
思考:
如果這樣寫會不會出現(xiàn)問題?接下來我們編寫一個(gè)測試類測試一下。
@SpringBootTest(classes = ShardingApplication.class)
@RunWith(SpringRunner.class)
public class TestShardingDatabase {
@Resource
PositionDao positionDao;
@Test
public void testQueryById() throws Exception{
PositionDO positionDO = positionDao.findPositionById(548083053407240192L);
System.out.println(positionDO);
}
}
哈哈,翻車了吧,還好先測試了一波,問題不大。
Hibernate: select t1.id, t1.name, t1.salary, t1.city, t2.description from position t1 left join position_detail t2 on t1.id = t2.pid where t1.id = ? org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [org.springframework.data.jpa.repository.query.AbstractJpaQuery$TupleConverter$TupleBackedMap] to type [com.lsp.dto.PositionDO]
分析原因:
那么到底是為什么造成這樣的原因呢?相信小伙伴們一眼就能看出來了,是因?yàn)镴pa找不到能夠從類型轉(zhuǎn)換的轉(zhuǎn)換器,而拋出這樣的異常。
現(xiàn)在問題來了,既然這樣不行,那么我們想要實(shí)現(xiàn)映射到自定義結(jié)果集該如何實(shí)現(xiàn)呢?
實(shí)現(xiàn):
JPA可以自定義SQL語句進(jìn)行查詢,然后查詢語句可以通過原生SQL語句(原生SQL語句也就是在@Query注解里加上nativeQuery = true)進(jìn)行查詢。當(dāng)然了,也可以通過JPQL進(jìn)行查詢。
我們這里就是通過JPQL進(jìn)行查詢,它的特征就是與原生SQL語句類似,完全面向?qū)ο螅ㄟ^類名和屬性訪問,而不是表名和表屬性。
由此PositionDao修改之后就像這樣
public interface PositionDao extends JpaRepository<Position, Long> {
@Query(value = "select new com.lsp.domain.PositionDO(t1.id, t1.name, t1.salary, t1.city, t2.description) \n" +
"from Position t1 left join PositionDetail t2 on t1.id = t2.pid \n" +
"where t1.id = :id")
PositionDO findPositionById(@Param("id") Long id);
}
接下來我們再運(yùn)行測試方法看一下。
Hibernate: select position0_.id as col_0_0_, position0_.name as col_1_0_, position0_.salary as col_2_0_, position0_.city as col_3_0_, positionde1_.description as col_4_0_ from position position0_ left outer join position_detail positionde1_ on (position0_.id=positionde1_.pid) where position0_.id=?
PositionDO{id=548083053407240192, name='Jerry5', salary=10000.00, city='beijing5', description='this is message 5'}
ok了,結(jié)果已經(jīng)正確查詢出來。
總結(jié):
注意上面的SQL語句是面向?qū)ο蟮?,對?yīng)的字段也都是實(shí)體類里面的屬性。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教。
相關(guān)文章
詳解 Java HashMap 實(shí)現(xiàn)原理
這篇文章主要介紹了詳解 Java HashMap 實(shí)現(xiàn)原理的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)使用Java,感興趣的朋友可以了解下2021-03-03
Mybatis-plus配置多數(shù)據(jù)源,連接多數(shù)據(jù)庫方式
這篇文章主要介紹了Mybatis-plus配置多數(shù)據(jù)源,連接多數(shù)據(jù)庫方式,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-06-06
java實(shí)戰(zhàn)CPU占用過高問題的排查及解決
這篇文章給大家分享了java實(shí)戰(zhàn)CPU占用過高問題的排查及解決方法,有需要的朋友們可以學(xué)習(xí)下。2018-08-08
使用MultipartFile來上傳單個(gè)及多個(gè)文件代碼示例
這篇文章主要介紹了使用MultipartFile來上傳單個(gè)及多個(gè)文件代碼示例,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01
Spring data jpa的使用與詳解(復(fù)雜動(dòng)態(tài)查詢及分頁,排序)
這篇文章主要介紹了Spring data jpa的使用與詳解(復(fù)雜動(dòng)態(tài)查詢及分頁,排序),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11
Java 序列化詳解及簡單實(shí)現(xiàn)實(shí)例
這篇文章主要介紹了 Java 序列化詳解及簡單實(shí)現(xiàn)實(shí)例的相關(guān)資料,使用序列化目的:以某種存儲形式使自定義對象持久化,將對象從一個(gè)地方傳遞到另一個(gè)地方,需要的朋友可以參考下2017-03-03
Java ThreadLocal詳解_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
ThreadLocal,很多地方叫做線程本地變量,也有些地方叫做線程本地存儲,本文會詳細(xì)的介紹一下,有興趣的可以了解一下2017-06-06
Java 使用Socket正確讀取數(shù)據(jù)姿勢
這篇文章主要介紹了Java 使用Socket正確讀取數(shù)據(jù)姿勢,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10

