问题概述:
JPA主要适用于强对象关系映射的场景,但是再做查询时需要返回的结果千差万别。所以,当我们使用非数据库对象作为返回结果对象时,
@Data
public class testDTO {
Integer ageSum;
Integer count;
}
@Repository
public interface TestDTORepository extends JpaRepository<testDTO, Long>, JpaSpecificationExecutor {
@Query(value = "select count(1) count,sum(age) ageSum from student",nativeQuery = true)
public testDTO get();
@Query(value = "select count(1) count,sum(age) ageSum from student",nativeQuery = true)
public List<testDTO> getList();
}
往往会启动报错。
Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Not a managed type: class com.example.demo.dao.testDTO
再网上收了好久,只有一种Object[]去接受返回结果的方法(Map,Json同样报上面的错)。
当然会感觉到很蠢,应为不看Sql的话,我们完全没办法知道数组中的每一位代表的是对象中的哪一个值。
苦思无果。
最后在stackoverflow上找到了还算可以的解决方法。
地址参考:https://stackoverflow.com/questions/44436287/nativequery-spring-data-return-object?r=SearchResults
再repository中定义接口,接口中方法为sql返回参数的对应get方法(其他方法测试无效)。
返回此接口对象。
改造后代码:
package com.example.demo.repository;
import com.example.demo.dao.User;
import com.example.demo.dao.testDTO;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface TestDTORepository extends JpaRepository<User, Long>, JpaSpecificationExecutor {
public interface CountAndAgeSum {
Integer getCount();
Integer getAgeSum();
}
@Query(value = "select count(1) count,sum(age) ageSum from student",nativeQuery = true)
public CountAndAgeSum get();
@Query(value = "select count(1) count,sum(age) ageSum from student",nativeQuery = true)
public List<CountAndAgeSum> getList();
}
那么接来的问题就好解决了。
可以通过放射去映射对象,从而得到你想要的对象。
如:
package com.example.demo.Util;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.stream.Collectors;
public class GetClassUtil {
public static Object getClass(Object obj, Class cla) throws IllegalAccessException, InstantiationException, InvocationTargetException {
Object c = cla.newInstance();
Method[] objMethodArray = obj.getClass().getDeclaredMethods();
Method[] claMethodArray = cla.getDeclaredMethods();
for (Method objMethod : objMethodArray) {
for (Method claMethod : claMethodArray) {
String claMethodName = claMethod.getName().toUpperCase();
String objMethodName = objMethod.getName().toUpperCase().replaceAll("GET", "");
if (claMethodName.startsWith("SET") && claMethodName.contains(objMethodName)) {
claMethod.invoke(c, objMethod.invoke(obj));
break;
}
}
}
return c;
}
public static List getClassList(List objList, Class cla) throws IllegalAccessException, InvocationTargetException, InstantiationException {
return (List) objList.stream().map(o -> {
try {
return GetClassUtil.getClass(o, cla);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}).collect(Collectors.toList());
}
}
该方法类的使用的话,可参考下面代码:
TestDTORepository.CountAndAgeSum c = testDTORepository.get();
testDTO t = null;
try {
t = (testDTO)GetClassUtil.getClass(c,testDTO.class);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}