Jpa Repository接口方法实现+自定义SQL返回map对象
文章结构
Spring Data Jpa 业务Repository接口实现
有时查询数据的时候需要连表或动态查询时,就需要自定义原生SQL去查询,一般有两种方法
1.在Service中新建一个方法去查询
2.在Repository定义一个接口,用方法去实现这个接口
第一个方法,Service中处理SQL数据库相关的业务,我个人觉得不太规范;这里主要讲第二种方法,步骤如下
1.在Repository定义一个接口
2.在接口类的同包下新建一个类,新建一个方法和接口中的方法名字,参数,返回数据 保存一致
3.在实现类中编写业务代码
自定义SQL查询结果返回map对象,或自定义对象
一般来说
Query.getResultList()
如果不做处理,返回的List中的对象是一个数组,这一般不是我们想要的;我们需要List中是对象,参考代码如下
示例代码
ProjectImgRepository.java - 业务Repository接口类
package com.itop.take_picture.repository;
@Repository
public interface ProjectImgRepository extends extends JpaRepository<ProjectImg, Long>, JpaSpecificationExecutor<ProjectImg> {
List<Map<String, Object>> statisticsCountByType(String startDate, String endDate, String projectId);
}
ProjectImgRepositoryImpl.java - 业务Repository接口实现类
package com.itop.take_picture.repository;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.query.internal.NativeQueryImpl;
import org.hibernate.transform.Transformers;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class ProjectImgRepositoryImpl {
@PersistenceContext
private EntityManager entityManager;
public List<Map<String, Object>> statisticsCountByType(String startDate, String endDate, String projectId) {
int i = 0;
Map<Integer, Object> param = new LinkedHashMap<>();
//组装sql语句
StringBuilder sql = new StringBuilder("SELECT count(1) FROM project_img b WHERE b.project_img_type_id = a.id");
if (StringUtils.isNotBlank(startDate)) {
sql.append(" AND b.create_time >= ?");
param.put(++i, startDate);
}
if (StringUtils.isNotBlank(endDate)) {
sql.append(" AND b.create_time <= ?");
param.put(++i, endDate);
}
if (StringUtils.isNotBlank(projectId)) {
sql.append(" AND b.project_id = ?");
param.put(++i, projectId);
}
sql.insert(0, "SELECT a.id, a.name, a.node_path, (");
sql.append(") as count FROM project_img_type a WHERE a.flag = 1");
//创建本地sql查询实例
Query dataQuery = entityManager.createNativeQuery(sql.toString());
//动态设置参数
for (Map.Entry<Integer, Object> entry : param.entrySet()) {
dataQuery.setParameter(entry.getKey(), entry.getValue());
}
// 将结果转化成map或自定义对象
// dataQuery.unwrap(NativeQueryImpl.class).setResultTransformer(Transformers.aliasToBean(ProjectImgStatisticsDTO.class));
dataQuery.unwrap(NativeQueryImpl.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
List<Map<String, Object>> resultList = dataQuery.getResultList();
return resultList;
}
}
注意事项
-
接口类和实现类名称务必统一规范,必须在同一个包下面,无需用implements与上面的接口产生正式的实现关系,但是还是要规范的实现上面的接口的方法;
-
dataQuery.setParameter(int var1, Object var2);
第一参数是从1开始,不是0开始,所以使用param.put(++i, xxx)
; -
可以通过
dataQuery.unwrap(NativeQueryImpl.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
将数组转化成map对象 -
dataQuery.unwrap(NativeQuery.class)
和dataQuery.unwrap(SQLQuery.class)
在Hibernaterv5.2之后已经作废,新版本的使用NativeQueryImpl.class
-
如果希望查询的结果是一个dto对象,可以这样写
dataQuery.unwrap(NativeQueryImpl.class).setResultTransformer(Transformers.aliasToBean(ProjectImgStatisticsDTO.class));