Spring data JPA只查詢(xún)部分字段問(wèn)題及解決
背景
在JPA查詢(xún)中,有時(shí)只需要查部分字段,這時(shí)jpa repository查出的是map,無(wú)法映射到Entity類(lèi)。
會(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)過(guò)驗(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ì)象
字段和查詢(xún)的字段對(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中定義查詢(xún)接口
@Query(name = "listExpressEbooks", nativeQuery = true) public List<EBookInfo> listExpressEbooks();
其它方案
查詢(xún)中構(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ù)里的寫(xiě)法,Blog需要提供相應(yīng)的構(gòu)造函數(shù)。
自己寫(xiě)convertor
repository 返回 Tuple 對(duì)象,自己寫(xiě)代碼手動(dòng)轉(zhuǎn)換為指定對(duì)象,repository層使用native查詢(xún)。
這里要借助輔助類(lèi):
class NativeResultProcessUtils { /** * tuple轉(zhuǎn)實(shí)體對(duì)象 * @param source tuple對(duì)象 * @param targetClass 目標(biāo)實(shí)體class * @param <T> 目標(biāo)實(shí)體類(lèi)型 * @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í)體類(lèi)型 * @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)類(lèi)的屬性信息 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); } //寫(xiě)入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ù)抽取收集,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-03-03SpringCloud+SpringBoot項(xiàng)目搭建結(jié)構(gòu)層次的實(shí)例
這篇文章詳細(xì)介紹了SpringCloud項(xiàng)目的架構(gòu)層次及其搭建經(jīng)驗(yàn),包括Controller層、Service層、Repository層、Entity層、DTO層、Exception層等,通過(guò)文字和圖片的形式,幫助讀者理解如何組織和實(shí)現(xiàn)一個(gè)SpringBoot項(xiàng)目的不同層次2025-01-01Java通過(guò)匿名類(lèi)來(lái)實(shí)現(xiàn)回調(diào)函數(shù)實(shí)例總結(jié)
這篇文章主要介紹了Java通過(guò)匿名類(lèi)來(lái)實(shí)現(xiàn)回調(diào)函數(shù)的例子,回調(diào)函數(shù)就是一種函數(shù)簽名(若干個(gè)輸入?yún)?shù)、一個(gè)輸出參數(shù))的規(guī)范,java雖不存在函數(shù)聲明,但是java可以用接口來(lái)強(qiáng)制規(guī)范。具體操作步驟大家可查看下文的詳細(xì)講解,感興趣的小伙伴們可以參考一下。2017-08-08MyBatis-Plus標(biāo)簽@TableField之fill自動(dòng)填充方式
這篇文章主要介紹了MyBatis-Plus標(biāo)簽@TableField之fill自動(dòng)填充方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06Eclipse+Maven構(gòu)建Hadoop項(xiàng)目的方法步驟
這篇文章主要介紹了Eclipse+Maven構(gòu)建Hadoop項(xiàng)目的方法步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-02-02Java:DocumentBuilderFactory調(diào)用XML的方法實(shí)例
Java:DocumentBuilderFactory調(diào)用XML的方法實(shí)例,需要的朋友可以參考一下2013-04-04