Spring Data JPA 連表動態條件查詢
阿新 • • 發佈:2020-08-06
多表查詢在spring data jpa中有兩種實現方式,第一種是利用hibernate的級聯查詢來實現(使用較為複雜,查詢不夠靈活),第二種是使用原生sql查詢。
JPA原生SQL連表查詢
@Repository public class SqlQueryRepository implements BaseQueryRepository { private static final String COUNT_REPLACEMENT_TEMPLATE = "select count(%s) $5$6$7"; /** * 匹配第三組,換成count(*),目前只用到simple */ private static final String SIMPLE_COUNT_VALUE = "$3*"; /** * 複雜查詢,count(主物件) */ private static final String COMPLEX_COUNT_VALUE = "$3$6"; private static final Pattern COUNT_MATCH; private static final String IDENTIFIER = "[\\p{Alnum}._$]+"; private static final String IDENTIFIER_GROUP = String.format("(%s)", IDENTIFIER); @PersistenceContext private EntityManager entityManager; // (select\s+((distinct )?(.+?)?)\s+)?(from\s+[\p{Alnum}._$]+(?:\s+as)?\s+)([\p{Alnum}._$]+)(.*) static { StringBuilder builder = new StringBuilder(); // from as starting delimiter builder.append("(?<=from)"); // at least one space separating builder.append("(?: )+"); // Entity name, can be qualified (any builder.append(IDENTIFIER_GROUP); // exclude possible "as" keyword builder.append("(?: as)*"); // at least one space separating builder.append("(?: )+"); // the actual alias builder.append("(\\w*)"); builder = new StringBuilder(); builder.append("(select\\s+((distinct )?(.+?)?)\\s+)?(from\\s+"); builder.append(IDENTIFIER); builder.append("(?:\\s+as)?\\s+)"); builder.append(IDENTIFIER_GROUP); builder.append("(.*)"); COUNT_MATCH = compile(builder.toString(), CASE_INSENSITIVE); } /** * 封裝原生sql分頁查詢,自動生成countSql * * @param pageable 分頁引數 * @param querySql 查詢sql,不包含排序 * @param orderSql 排序sql * @param paramMap 引數列表 * @param clazz 返回物件class * @param <T> 返回物件 * @return PageImpl */ @Override public <T> Page<T> queryPageable(String querySql, String orderSql, Map<String, Object> paramMap, Pageable pageable, Class<T> clazz) { String countSql = createCountQuery(querySql); Query countQuery = (Query)this.entityManager.createNativeQuery(countSql); Query query = (Query)this.entityManager.createNativeQuery(querySql + orderSql); // 設定引數 if (paramMap != null && paramMap.size() > 0) { for (Map.Entry<String, Object> entry : paramMap.entrySet()) { countQuery.setParameter(entry.getKey(), entry.getValue()); query.setParameter(entry.getKey(), entry.getValue()); } } BigInteger totalCount = (BigInteger) countQuery.getSingleResult(); query.setFirstResult((int) pageable.getOffset()); query.setMaxResults(pageable.getPageSize()); // 不使用hibernate轉bean,存在資料型別問題 //query.setResultTransformer(Transformers.aliasToBean(clazz)); query.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP); List<T> resultList = JSON.parseArray(JSON.toJSONString(query.getResultList(), SerializerFeature.WriteMapNullValue), clazz); return new PageImpl<>(resultList, pageable, totalCount.longValue()); } /** * 根據查詢sql自動生成countSql,正則匹配 * * @param sql 查詢sql * @return countSql */ public String createCountQuery(String sql) { Matcher matcher = COUNT_MATCH.matcher(sql); return matcher.replaceFirst(String.format(COUNT_REPLACEMENT_TEMPLATE, SIMPLE_COUNT_VALUE)); } }
使用示例
@Repository public class RiskChangeDaoImpl implements RiskChangeNativeDao { @Autowired private BaseQueryRepository baseQueryRepository; @Override public Page<RiskChange> getRiskChangePageable(String tenantId, String userId, RiskMonitorDTO riskMonitorDTO, PageRequest pageable) { // 拼接查詢sql StringBuilder selectSql = new StringBuilder(); selectSql.append("SELECT rc.id id, rc.pk_risk_change pkRiskChange, rc.pk_risk pkRisk, rc.change_date changeDate, rc.company_id companyId, "); selectSql.append("rc.company_name companyName, rc.risk_level riskLevel, rc.risk_type riskType, rc.risk_content riskContent "); selectSql.append("FROM dv_risk_sub rs,dv_risk_change rc "); selectSql.append("WHERE rs.user_id = :userId AND rs.tenant_id = :tenantId AND rs.dr = 0 "); selectSql.append("AND rs.company_id = rc.company_id AND rc.change_date >= rs.sub_date "); HashMap<String, Object> paramMap = new HashMap<>(16); paramMap.put("userId", userId); paramMap.put("tenantId", tenantId); StringBuilder whereSql = new StringBuilder(); // 企業名稱模糊篩選 if (StringUtils.isNotBlank(riskMonitorDTO.getCompanyName())) { whereSql.append(" AND rs.company_name like :companyName "); paramMap.put("companyName", "%" + riskMonitorDTO.getCompanyName() + "%"); } // 風險型別篩選 in if (!CollectionUtils.isEmpty(riskMonitorDTO.getRiskTypes())) { whereSql.append(" AND rc.risk_type in :riskType "); paramMap.put("riskType", riskMonitorDTO.getRiskTypes()); } if (StringUtils.isNotBlank(riskMonitorDTO.getStartChangeDate())) { whereSql.append(" AND rc.change_date >= :startChangeDate "); paramMap.put("startChangeDate", riskMonitorDTO.getStartChangeDate()); } if (StringUtils.isNotBlank(riskMonitorDTO.getEndChangeDate())) { whereSql.append(" AND rc.change_date <= :endChangeDate "); paramMap.put("endChangeDate", riskMonitorDTO.getEndChangeDate()); } // 新增排序 String orderSql = " ORDER BY changeDate desc, companyId desc "; String querySql = selectSql.append(whereSql).toString(); return baseQueryRepository.queryPageable(querySql, orderSql, paramMap, pageable, RiskChange.class); } }