package com.demo.jpa_query_test.respository;
import com.demo.jpa_query_test.model.Stu;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.jdbc.core.JdbcTemplate;
import java.awt.print.Pageable;
import java.util.List;
/**
* 一个学生和班级多对一
* 一个学生和汽车多对多
*/
public interface StuRespository extends JpaRepository<Stu,Integer> {
//这是接口不能注入jdbcTemplate 要想用自己新建个studao类 可以把jdbcTemplate和StuRespository都注入进入
@Override
<S extends Stu> S save(S s);
@Override
List<Stu> findAll();
//多对一查询,想要查询学生 根据其所在的班级id
//inner join为内连接查询,左右都必须有值,右边的IClass必须返回实体,不然查询的结果为bull
//不用写外键关系 s.iclass c 包含了外键关系,右表还必须这样写
@Query(value = "select s from Stu s inner join s.iclass c where c.id = :size ")
List<Stu> findByCarSize(@Param(value = "size") Integer size);
//多对一查询,想要查询学生 根据其所在的班级id
//left join为内连接查询,以左边为基础,右边的IClass可以返回null
//不用写外键关系 s.iclass c 包含了外键关系,右表还必须这样写
@Query(value = "select s from Stu s left join s.iclass c where c.id = :size ")
List<Stu> findByCarSize2(@Param(value = "size") Integer size);
/**转换后的hibernate语句
* Hibernate: select stu0_.id as id1_2_, stu0_.c_id as c_id3_2_, stu0_.name as name2_2_ from stu stu0_ where (select count(carlist1_.stu_id) from sut_car_relation carlist1_ where stu0_.id=carlist1_.stu_id)>=?
* //多对多查询,原始的sql要查询左表+中间表 或者右表+中间表
* //jpql 有size() concate()等函数可用
* //查询拥有汽车数大于2的学生
*/
@Query(value = "select s from Stu s where size(s.carList)>= :size ")
List<Stu> findByCarSize3(@Param(value = "size") Integer size);
/**
* 使用原生的sql 查询学生 按照拥有的汽车数排序,学生和汽车多对多
* 先使用子查询 得到stu_id 和 统计数这个中间表 c 拿这个中间表(带汽车统计个数和学生id)和学生表内连接 得到交叉集合
*
* @return
*/
@Query(value = " select s.* from stu s ,(select sc.stu_id ,count(sc.stu_id) as coun_t from sut_car_relation sc group by sc.stu_id) as c where s.id = c.stu_id order by c.coun_t asc" ,nativeQuery = true)
List<Stu> findByCarSize4();
/**
* 使用jpql查询没有 车的学生 is null 判断null is empty只能判断实体的集合属性是否为空
* @return
*/
@Query(value = "select s from Stu s where s.carList is empty ")
List<Stu> findByCarSize6();
/**
* 使用jpql就简单的多了 直接如下
* @return
*/
@Query(value = "select s from Stu s order by size(s.carList) desc")
List<Stu> findByCarSize5();
/**
* spring boot分页
* 前边传入分页参数
* Pageable pageable = new PageRequest(currentPage, pagesize, Sort.Direction.DESC, "keywords");
* currentPage从0页开始
*/
@Query(value = "from Stu s where 1=1")
List<Stu> findByIPage_w();
/**
* 使用自带的分页page 该对象里面总条数。。这些都有了
* //这是spring boot 2.0 pageable必写全路径,不然就
* @Param on all parameters except Pageable and Sort typed once, or none at all_。。
* @param name
* @param pageable
* @return
*/
@Query(value = "select s from Stu s where s.name = :name")
Page<Stu> findAllTest1(@Param(value = "name") String name,org.springframework.data.domain.Pageable pageable);
/**
* jpql 支持动态传参数,?1 或者:name 这种,同时只能使用一种
*
*/
@Query(value = "from Stu s where s.name = ?1 and s.id = ?2")
Stu findByNameAndId(String name,String id);
/***
* 动态sql
* 原始的sql
* IF( expr1 , expr2 , expr3 ) expr1 的值为 TRUE,则返回值为 expr2 ,expr1 的值为FALSE,则返回值为 expr3
* 例如 if(/"/"=:name,1=1, s.name like concat('%',:name,'%'))
* if(:stae is null,1=1, s.state = :state)
*
* @Query(value = "select * from tag_info T where (1=1 and if(:tagState is null ,1=1,T.tag_state=:tagState) and T.tag_type in :tagType and if(\"\"=:content,1=1,T.name like CONCAT('%',:content,'%'))) or (1=1 and T.id in :ids) order by :orderFiled :px limit :start , :ed", nativeQuery = true)
*
* IFNULL( expr1 , expr2 ) 在 expr1 的值不为 NULL的情况下都返回 expr1,否则返回 expr2
*/
//在拼接sql的过程中,传来的参数有字符串,Integer Boolean等 都可以判断为"" 或者为null
//但 in 集合或者数组,没法判断 他们也可能为空,in () 报错 ,前台可以给个默认值,默全部,如果前台传来的为空 就用全部,不为空就用前台的,或者故意往集合添加一个无关紧要的
/**
* jpql无法动态拼接sql只能用原始的
*/
//删除更新操作 要加@Modifying
@Query("delete from Stu s where s.name = ?1")
@Modifying
void delByName(String name);
}
只查询几个字段,让结果封装到到List<Map<String,Object>>中,或者封装到list<Object[ ]> 中,不支持自定义封装的vo ,而且实体的实体的字段必须每个都有,不然封装就报错,
排除用实体封装几个字段的思想
public class Test(){
//类中注入 实体管理器,用实体管理器查询 返回的结果 List<Map<String, Object>> 有字段名字
@PersistenceContext(unitName = "manageFactory")
protected EntityManager em;
public List<Map<String, Object>>getListMap(String sql){
Query nativeQuery=em.createNativeQuery(sql);
nativeQuery.unwrap(NativeQueryImpl.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
List resultList=nativeQuery.getResultList();
return resultList;
}
}
上边这种用实体管理器的原生查询,没有加入设置参数,下边是优化过的,可以防止sql 注入,还可以设置分页
@PersistenceContext
EntityManager entityManager;
@Override
public Object findMeetingSignRecoredPage(Long meetingId, Integer pageIndex, Integer pageSize) {
MeenoAssert.notNull(meetingId, ErrEnum.MEETING_ID_IS_EMPTY);
Meeting meeting = this.meetingRepository.getOne(meetingId);
MeenoAssert.notNull(meeting,ErrEnum.MEETING_IS_NOT_EXIST);
Pageable pageable = PageUtils.getPageable(pageIndex,pageSize);
StringBuilder sql = new StringBuilder();
sql.append(" select ep.name,MAX(r.sign) from mnt_emp_rel_meeting as e ");
sql.append(" left join mnt_sign_record as r on(r.employee_id=e.employee_id) ");
sql.append(" left join mnt_employee as ep on(ep.id = e.employee_id) ");
sql.append(" where e.meeting_id = ? ");
sql.append(" order by r.sign desc,r.create_date asc ");
Query query = entityManager.createNativeQuery(sql.toString());
query.setFirstResult(pageable.getOffset());
query.setMaxResults(pageable.getPageSize());
query.setParameter(1,meetingId);
List<Object[]> list = query.getResultList();
List<SignRecordView> listView = Lists.newArrayList();
if(list != null && !list.isEmpty()){
for (Object[] objects : list) {
String empName = objects[0]==null?null:objects[0].toString();
Integer sign = objects[1]==null?Constants.SIGN_RECORD_NO:Integer.parseInt(objects[1].toString());
SignRecordView view = new SignRecordView();
view.setEmployeeName(empName);
view.setSign(sign);
listView.add(view);
}
}
//count
StringBuilder countSql = new StringBuilder();
countSql.append(" select count(distinct e.id) from mnt_emp_rel_meeting as e ");
countSql.append(" left join mnt_sign_record as r on(r.employee_id=e.employee_id) ");
countSql.append(" left join mnt_employee as ep on(ep.id = e.employee_id) ");
countSql.append(" where e.meeting_id = ? ");
countSql.append(" order by r.sign desc,r.create_date asc ");
Query countQuery = entityManager.createNativeQuery(countSql.toString());
countQuery.setParameter(1,meetingId);
Object singleResult = countQuery.getResultList().get(0);
Integer count = singleResult==null?0:Integer.valueOf(singleResult.toString());
Map<String, Object> resultPage = PageUtils.getResultPage(count, listView);
return resultPage;
}
//这种返回的每一行是个数组,没有字段名称
@Query(value = "select project_name,id from automatic_project order by create_date desc",nativeQuery = true)
List<Object[]> findAllProjectName();
如果查询几个字段,包含多表中的各个几个字段,也可以用jpql查询的 自定义Model
public class MyModel implements Serializable {
private String userName;
private String name;
private String gender;
private String description;
public MyModel() {};
public MyModel(String userName, String name, String gender, String description) {
this.userName = userName;
this.name = name;
this.gender = gender;
this.description = description;
}
}
//pers.zhuch.model自己的包路径
@Query(value = "select new pers.zhuch.model.MyModel(u.userName, ui.name, ui.gender, ui.description) from UserInfo ui, User u where u.id = ui.userId")
public List<MyModel> getAllRecord();
//如果不想封装自己的model可以直接用 map
第二种方法:在service 里边转换成 JSON
原理其实和第一种方法差不多,只是处理结果的方式不太一样,只是这种方法我们就不在 hql 中 new Model 了,直接写查询方法
@Query(value = "select new map(u.userName, ui.name, ui.gender, ui.description) from UserInfo ui, User u where u.id = ui.userId")
public List<Map<String, Object>> getCustomField();
用接口形式的vo 来封装部分结果
@Query(value = "SELECT p.project_name as projectName,count(t.id) as taskNum FROM automatic_project p ,automatic_task t WHERE p.id = t.project_id GROUP BY t.project_id /*#pageable*/ ",countQuery = "SELECT p.project_name as projectName,count(t.id) as taskNum FROM automatic_project p ,automatic_task t WHERE p.id = t.project_id GROUP BY t.project_id ",nativeQuery = true)
Page<Myvo> getAllByPageVo(Pageable pageable);
@Query(value = "SELECT p.project_name as projectName,count(t.id) as taskNum FROM automatic_project p ,automatic_task t WHERE p.id = t.project_id GROUP BY t.project_id /*#pageable*/ ",nativeQuery = true)
List<Myvo> getAllByPageList();
//接口形式的vo 注意get字段名
package com.trs.jxwy.financial.web.vo.automatic;
public interface Myvo {
Integer getTaskNum();
String getProjectName();
}
//service
PageRequest pageable = new PageRequest(pageNo - 1, pageSize, Sort.Direction.DESC, "create_date");
Page<Myvo> allByPageVo2=automaticProjectRepository.getAllByPageVo(pageable);
List<Myvo> allByPageList=automaticProjectRepository.getAllByPageList();