SpringData Jpa 的JPQL 多表关联查询

package com.touchhealth.trade.service.afterSale;

import com.touchealth.common.page.Pager;
import com.touchhealth.trade.bo.afterSale.AfterSaleBo;
import com.touchhealth.trade.entity.AfterSaleDo;
import com.touchhealth.trade.entity.afterSale.AfterSale;
import com.touchhealth.trade.helper.afterSale.AfterSaleHelper;
import com.touchhealth.trade.repository.afterSale.AfterSaleRepository;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @Auther: dangshilin
 * @Date: 2018/7/30
 */
@Service("afterSaleService")
public class AfterSaleServiceImpl implements AfterSaleService{

    @Autowired
    private AfterSaleRepository afterSaleRepository;

    @PersistenceContext
    private EntityManager em;


    /**
     * 分页获取售后单列表
     * @param afterSaleBo
     * @param pager
     * @return
     */
    @Override
    public Pager list(AfterSaleBo afterSaleBo, Pager pager) {
        String makerMobile = afterSaleBo.getMakerMobile();
        Integer applyType = afterSaleBo.getApplyType();
        Date endTime = afterSaleBo.getEndTime();
        Date startTime = afterSaleBo.getStartTime();
        String sourceCode = afterSaleBo.getSourceCode();
        Integer processState = afterSaleBo.getProcessState();
        int pageSize = pager.getPageSize();
        int pageNo = pager.getPageNo();
        int begin = pager.getPageSize()*(pager.getPageNo()-1);
        // 查询售后申请单的jpql
        String sql = "select new com.touchhealth.trade.entity.AfterSaleDo (a.id,a.afterSaleNo,a.reservationNo,a.makerId,a.makerName,a.makerMobile,a.createdAt,a.applyReason,a.examineFailReason,a.applyExpectTime,a.firstReservationTime,a.processState,a.applyType,a.deleteFlag,a.updatedAt,a.updatedOperatorId,a.updatedOperatorName,a.deletedAt,a.deletedOperatorId,a.deletedOperatorName,a.remark,s.sourceCode) from AfterSale a,Source s,Reservation r where a.reservationNo = r.reservationNo and r.id = s.typeObjectId and s.type = 1";
        // 查询数量sql
        String countSql = "select count(*) from t_after_sale a,t_source s,t_reservation r where a.reservation_no = r.reservation_no and r.id = s.type_object_id and s.type = 1";
        // 动态参数
        List<Object> params = new ArrayList<>();
        int i = 1;
        int j = 1;
        if (StringUtils.isNotBlank(makerMobile)) {
            sql = sql + " and a.makerMobile = ?" + i++;
            countSql = countSql + " and a.maker_mobile = ?" + j++;
            params.add(makerMobile);
        }
        if (null != applyType){
            sql = sql + " and a.applyType = ?" + i++;
            countSql = countSql + " and a.apply_type = ?" + j++;
            params.add(applyType);
        }
        if (StringUtils.isNotBlank(sourceCode)){
            sql = sql + " and s.sourceCode = ?" + i++;
            countSql = countSql + " and s.source_code = ?" + j++;
            params.add(sourceCode);
        }
        if (null != startTime){
            Date createdAt = startTime;
            sql = sql + " and s.createdAt >= ?" + i++;
            countSql = countSql + " and s.created_at >= ?" + j++;
            params.add(createdAt);
        }
        if (null != endTime){
            Date createdAt = endTime;
            sql = sql + " and a.createdAt <= ?" + i++;
            countSql = countSql + " and a.created_at <= ?" + j++;
            params.add(createdAt);
        }
        if (null != processState){
            sql = sql + " and a.processState = ?" + i++;
            countSql = countSql + " and a.process_state = ?" + j++;
            params.add(processState);
        }else {
            // 申请单流程状态 1-待审核 2-审核通过 3-审核失败 4-已取消
            sql = sql + " and a.processState in (2,3,4)";
            countSql = countSql + " and a.process_state in (2,3,4)";
        }
        sql = sql + " ORDER by a.createdAt DESC ";
        countSql = countSql + " ORDER by a.created_at DESC ";
        Query query = em.createQuery(sql);
        Query countQuery = em.createNativeQuery(countSql);
        for (int k = 1; k < params.size() + 1; k++) {
            query.setParameter(k, params.get(k - 1));
            countQuery.setParameter(k, params.get(k - 1));
        }
        query.setFirstResult(begin);
        query.setMaxResults(pageSize);
        List<AfterSaleDo> resultList = query.getResultList();
        // 关闭资源
        em.close();
        pager.setResultList(AfterSaleHelper.convertAfterSaleDoListToAfterSaleBoList(resultList));
        BigInteger count = (BigInteger)countQuery.getSingleResult();
        double records = count.intValue();
        pager.setRecords((int) records);
        double total = records/pageSize;
        pager.setTotal((int) Math.ceil(total));
        return pager;
    }


    /**
     * 筛选获取售后申请单列表
     * @param afterSaleBo
     * @return
     */
    @Override
    public List<AfterSaleBo> exportList(AfterSaleBo afterSaleBo) {
        String makerMobile = afterSaleBo.getMakerMobile();
        Integer applyType = afterSaleBo.getApplyType();
        Date endTime = afterSaleBo.getEndTime();
        Date startTime = afterSaleBo.getStartTime();
        String sourceCode = afterSaleBo.getSourceCode();
        Integer processState = afterSaleBo.getProcessState();
        // 查询售后申请单的jpql
        String sql = "select new com.touchhealth.trade.entity.AfterSaleDo (a.id,a.afterSaleNo,a.reservationNo,a.makerId,a.makerName,a.makerMobile,a.createdAt,a.applyReason,a.examineFailReason,a.applyExpectTime,a.firstReservationTime,a.processState,a.applyType,a.deleteFlag,a.updatedAt,a.updatedOperatorId,a.updatedOperatorName,a.deletedAt,a.deletedOperatorId,a.deletedOperatorName,a.remark,s.sourceCode,r.serviceItemName,r.reservedPartyName,r.reservationPartyInfo) from AfterSale a,Source s,Reservation r where a.reservationNo = r.reservationNo and r.id = s.typeObjectId and s.type = 1";
        // 动态参数
        List<Object> params = new ArrayList<>();
        int i = 1;
        if (StringUtils.isNotBlank(makerMobile)) {
            sql = sql + " and a.makerMobile = ?" + i++;
            params.add(makerMobile);
        }
        if (null != applyType){
            sql = sql + " and a.applyType = ?" + i++;
            params.add(applyType);
        }
        if (StringUtils.isNotBlank(sourceCode)){
            sql = sql + " and s.sourceCode = ?" + i++;
            params.add(sourceCode);
        }
        if (null != startTime){
            Date createdAt = startTime;
            sql = sql + " and s.createdAt >= ?" + i++;
            params.add(createdAt);
        }
        if (null != endTime){
            Date createdAt = endTime;
            sql = sql + " and a.createdAt <= ?" + i++;
            params.add(createdAt);
        }
        if (null != processState){
            sql = sql + " and a.processState = ?" + i++;
            params.add(processState);
        }else {
            // 申请单流程状态 1-待审核 2-审核通过 3-审核失败 4-已取消
            sql = sql + " and a.processState in (2,3,4)";
        }
        sql = sql + " ORDER by a.createdAt DESC ";
        Query query = em.createQuery(sql);
        for (int k = 1; k < params.size() + 1; k++) {
            query.setParameter(k, params.get(k - 1));
        }
        List<AfterSaleDo> resultList = query.getResultList();
        // 关闭资源
        em.close();
        List<AfterSaleBo> afterSaleBoList = AfterSaleHelper.convertAfterSaleDoListToAfterSaleBoList(resultList);
        return afterSaleBoList;
    }
}

以上是业务层代码.

@Autowired
private AfterSaleRepository afterSaleRepository; 


持久层的服务就不解释了.

@PersistenceContext
private EntityManager em;

Persistence context是由一组受托管的实体对象实例所构成的集合。它受entity manager 的管理。Entity manager追踪persistence context中所有对象的修改和更新情况,并根据指定的flush模式将这些修改保存到数据库中。一旦persistence context被关闭,所有实体对象实例都会脱离EntityManager而成为非托管对象。对象一旦从persistence context中脱离,就不再受entity manager管理了,任何对此对象的状态变更也将不会被同步到数据库。Java Persistence中有两种类型的persistence context,分别是transaction-scoped persistence context和extended persistence context。Transaction-scoped persistence context的persistence context可能只在事务范围内存在,它们会在事务结束后被关闭。当事务结束时,transaction-scoped persistence context将被销毁,而所有的托管实体对象实例也将处于游离状态(detached)。只有受应用服务器管理的persistence context才可以是事务范围的。换言之,只有标注了@PersistenceContext注解(或是其XML的等价描述)的EntityManager实例才可以是事务范围的。

注意:

第一个坑:

因为Persistence context是由一组受托管的实体对象实例所构成的集合,并且受entity manager 的管理.所以拼接的sql 中 "......from AfterSale a,Source s,Reservation r......"AfterSale,Source,Reservation是数据库表映射的实体类的名字,而不是表名.查询的内容是实体类的属性而不是数据库表字段.又因为NativeQuery使用的是使用HQL查询,所以拼接的countSql中对应的是数据库表名和数据库子段名.

第二个坑:

查询结果需要一个对象来接收.这个对象除了要提供set,get方法还需要提供一个与之对应的有参构造方法.注意,是与结果属性完全对应的有参构造方法.

如果不需要分页的话,把countSql相关的和Pager相关的去掉就好了.以上仅是个人浅见,如有错误,欢迎指正!

猜你喜欢

转载自blog.csdn.net/qq_40074764/article/details/81348937