Spring data JPA只查詢部分字段問題及解決
背景
在JPA查詢中,有時(shí)只需要查部分字段,這時(shí)jpa repository查出的是map,無法映射到Entity類。
會(huì)提示錯(cuò)誤:
org.springframework.core.convert.ConverterNotFoundException:
No converter found capable of converting from type
[org.springframework.data.jpa.repository.query.AbstractJpaQuery$TupleConverter$TupleBackedMap] to type
網(wǎng)上搜索有多種解決方案。這里列舉一下。
經(jīng)過驗(yàn)證,本人采取了第一種方案,證明是可行的。
JPA 2.1以上的解決辦法
實(shí)體中增加named query和result map
@SqlResultSetMapping(name = "EBookInfo",
classes = @ConstructorResult(targetClass = EBookInfo.class,
columns = {
@ColumnResult(name = "book_id", type = Long.class),
@ColumnResult(name = "book_name", type = String.class),
@ColumnResult(name = "file_type", type = String.class)
}))
@NamedNativeQuery(name = "listExpressEbooks",
query = "select book_id, book_name, file_type from ebook order by update_date desc",
resultSetMapping = "EBookInfo")
@Entity
@Table(name = "ebook")
public class Ebook {
private Long bookId;
private Integer authorId;
private String authorName;
private Integer categoryId;
private String bookName;
private String subTitle;
private String tags;
private String isbn;
private String edition;
private Byte bookType;
private Integer star;
private Integer downloadCount;
private Byte status;
private String fileType;
private String outline;
private String introduction;
private String preface;
private String cover;
private Float price;
private String publisher;
private String bgColor;
private String foreColor;
private String titleColor;
private String coverBackgroundId;
private String coverPictureId;
private Integer coverTemplateId;
private String coverPictureMode;
private Integer pageMode;
private Timestamp requestDate;
private Timestamp publishDate;
private Timestamp updateDate;
定義一個(gè)新的DTO對(duì)象
字段和查詢的字段對(duì)應(yīng),需要提供構(gòu)造函數(shù):
@Data
public class EBookInfo {
private Long bookId;
private String bookName;
private String fileType;
public EBookInfo(Long bookId, String bookName, String fileType) {
this.bookId = bookId;
this.bookName = bookName;
this.fileType = fileType;
}
}
repository中定義查詢接口
@Query(name = "listExpressEbooks", nativeQuery = true)
public List<EBookInfo> listExpressEbooks();其它方案
查詢中構(gòu)造新對(duì)象
public List<Blog> selectByYearMonth(String year, String month, int status) {
String sql = String.format("select new Blog(blog.id, blog.title, blog.abs, blog.createtime) from Blog blog where blog.status = %d and YEAR(createtime) = %s and MONTH(createtime) = %s order by blog.createtime desc", status, year, month);
//Query query = this.em.createNativeQuery(sql, "ExpressedResult");
Query query = this.em.createQuery(sql);
List results = query.getResultList();
return results;
}上述方法是之前我項(xiàng)目中代碼庫(kù)里的寫法,Blog需要提供相應(yīng)的構(gòu)造函數(shù)。
自己寫convertor
repository 返回 Tuple 對(duì)象,自己寫代碼手動(dòng)轉(zhuǎn)換為指定對(duì)象,repository層使用native查詢。
這里要借助輔助類:
class NativeResultProcessUtils {
/**
* tuple轉(zhuǎn)實(shí)體對(duì)象
* @param source tuple對(duì)象
* @param targetClass 目標(biāo)實(shí)體class
* @param <T> 目標(biāo)實(shí)體類型
* @return 目標(biāo)實(shí)體
*/
public static <T> T processResult(Tuple source,Class<T> targetClass) {
Object instantiate = BeanUtils.instantiate(targetClass);
convertTupleToBean(source,instantiate,null);
return (T) instantiate;
}
/**
*
* tuple轉(zhuǎn)實(shí)體對(duì)象
* @param source tuple對(duì)象
* @param targetClass 目標(biāo)實(shí)體class
* @param <T> 目標(biāo)實(shí)體類型
* @param ignoreProperties 要忽略的屬性
* @return 目標(biāo)實(shí)體
*/
public static <T> T processResult(Tuple source,Class<T> targetClass,String... ignoreProperties) {
Object instantiate = BeanUtils.instantiate(targetClass);
convertTupleToBean(source,instantiate,ignoreProperties);
return (T) instantiate;
}
/**
* 把tuple中屬性名相同的值復(fù)制到實(shí)體中
* @param source tuple對(duì)象
* @param target 目標(biāo)對(duì)象實(shí)例
*/
public static void convertTupleToBean(Tuple source,Object target){
convertTupleToBean(source,target,null);
}
/**
* 把tuple中屬性名相同的值復(fù)制到實(shí)體中
* @param source tuple對(duì)象
* @param target 目標(biāo)對(duì)象實(shí)例
* @param ignoreProperties 要忽略的屬性
*/
public static void convertTupleToBean(Tuple source,Object target, String... ignoreProperties){
//目標(biāo)class
Class<?> actualEditable = target.getClass();
//獲取目標(biāo)類的屬性信息
PropertyDescriptor[] targetPds = BeanUtils.getPropertyDescriptors(actualEditable);
//忽略列表
List<String> ignoreList = (ignoreProperties != null ? Arrays.asList(ignoreProperties) : null);
//遍歷屬性節(jié)點(diǎn)信息
for (PropertyDescriptor targetPd : targetPds) {
//獲取set方法
Method writeMethod = targetPd.getWriteMethod();
//判斷字段是否可以set
if (writeMethod != null && (ignoreList == null || !ignoreList.contains(targetPd.getName()))) {
//獲取source節(jié)點(diǎn)對(duì)應(yīng)的屬性
String propertyName = targetPd.getName();
Object value = source.get(propertyName);
if(value!=null && ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], value.getClass())) {
try {
//判斷target屬性是否private
if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
writeMethod.setAccessible(true);
}
//寫入target
writeMethod.invoke(target, value);
}
catch (Throwable ex) {
throw new FatalBeanException(
"Could not copy property '" + targetPd.getName() + "' from source to target", ex);
}
}
}
}
}
}
使用entityManager的Transformers.aliasToBean
未驗(yàn)證,Spring data jpa未必支持
使用entityManager的Transforms.ALIAS_TO_ENTITY_MAP
未驗(yàn)證
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
基于Java8 Stream API實(shí)現(xiàn)數(shù)據(jù)抽取收集
這篇文章主要介紹了基于Java8 Stream API實(shí)現(xiàn)數(shù)據(jù)抽取收集,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-03-03
SpringCloud+SpringBoot項(xiàng)目搭建結(jié)構(gòu)層次的實(shí)例
這篇文章詳細(xì)介紹了SpringCloud項(xiàng)目的架構(gòu)層次及其搭建經(jīng)驗(yàn),包括Controller層、Service層、Repository層、Entity層、DTO層、Exception層等,通過文字和圖片的形式,幫助讀者理解如何組織和實(shí)現(xiàn)一個(gè)SpringBoot項(xiàng)目的不同層次2025-01-01
Java通過匿名類來實(shí)現(xiàn)回調(diào)函數(shù)實(shí)例總結(jié)
這篇文章主要介紹了Java通過匿名類來實(shí)現(xiàn)回調(diào)函數(shù)的例子,回調(diào)函數(shù)就是一種函數(shù)簽名(若干個(gè)輸入?yún)?shù)、一個(gè)輸出參數(shù))的規(guī)范,java雖不存在函數(shù)聲明,但是java可以用接口來強(qiáng)制規(guī)范。具體操作步驟大家可查看下文的詳細(xì)講解,感興趣的小伙伴們可以參考一下。2017-08-08
MyBatis-Plus標(biāo)簽@TableField之fill自動(dòng)填充方式
這篇文章主要介紹了MyBatis-Plus標(biāo)簽@TableField之fill自動(dòng)填充方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06
Eclipse+Maven構(gòu)建Hadoop項(xiàng)目的方法步驟
這篇文章主要介紹了Eclipse+Maven構(gòu)建Hadoop項(xiàng)目的方法步驟,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-02-02
Java:DocumentBuilderFactory調(diào)用XML的方法實(shí)例
Java:DocumentBuilderFactory調(diào)用XML的方法實(shí)例,需要的朋友可以參考一下2013-04-04

