Specifications动态查询
* 继承了JpaSpecificationExecutor<T>中的方法
//根据条件查询一个对象
T findOne(Specification<T> spec);
//根据条件查询集合
List<T> findAll(Specification<T> spec);
//根据条件分页查询
Page<T> findAll(Specification<T> spec, Pageable pageable);
//排序查询查询
List<T> findAll(Specification<T> spec, Sort sort);
//统计查询
long count(Specification<T> spec);
* Specification:查询条件
自定义我们自己的Specification实现类
实现
1. root:查询的根对象(查询的任何属性都可以从根对象中获取)
2. CriteriaQuery:顶层查询对象,自定义查询方式(了解即可,一般不使用)
3. CriteriaBuilder:查询构造器,封装了很多的查询条件
Predicate toPredicate(Root<T> root,CriteriaQuery<?> query,CriteriaBuilder cb);
* 代码
@Test
public void testEquals(){
Customer c = dao.findOne(new Specification<Customer>() {
public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
Path<Object> custId = root.get("custId");
Predicate predicate = criteriaBuilder.equal(custId, 1l);
return predicate;
}
});
System.out.println(c);
}
/**
* testNoAsString
* 在path写上String就不用再写as.(String.class)
*
*/
@Test
public void testNoAsString() throws Exception{
Customer customer = dao.findOne(new Specification<Customer>() {
public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
Path<String> custName = root.get("custName");
Predicate predicate = criteriaBuilder.like(custName, "ha%");
return predicate;
}
});
System.out.println(customer);
}
/**
* 测试分页查询
* Pageable
*/
@Test
public void testPageSelect()throws Exception{
Page<Customer> page = dao.findAll(new PageRequest(0, 5));
//返回的总页数
System.out.println(page.getTotalPages());
//返回的总记录数
System.out.println(page.getTotalElements());
//返回的内容集合
System.out.println(page.getContent());
}
/**
* 排序查询
*/
@Test
public void testSortSelect() throws Exception{
//倒序查询,根据custId属性倒序
List<Customer> list = dao.findAll(new Sort(Sort.Direction.DESC,"custId"));
for (Customer customer : list) {
System.out.println(customer);
}
}
多表之间的关系和操作多表的操作步骤
表关系:
一对一
主键映射(两个表的主键相同),外键映射(在一个表中设置外键来对应另一张表的主键)
一对多
一的一方:主表
多的一方:从表
外键:需要在从表上新建一列作为外键,取值来源于主表的主键
多对多
中间表:至少有两个字段组成
实体类中的关系:
包含关系:可以通过实体类中的包含关系描述表关系
继承关系:
步骤:
1. 明确表关系
2. 确定表关系(描述:外键|中间表)
3. 编写实体类,在实体类中描述表关系(包含|继承)
4. 配置映射关系
多表操作练习
* 一般我们不会进行双向关联,只会保存可以维护中间表/外键的一方
1. 一对多:
1. 建立表之间的关联关系(实体类之间的关系)
Customer(一的一方)
//配置一对多的关系
//@OneToMany(targetEntity = LinkMan.class)
//@JoinColumn(name = "lkm_cust_id",referencedColumnName = "cust_id")
//放弃维护外键(一般一的一方会放弃外键的维护)
@OneToMany(mappedBy = "customer")
private Set<LinkMan> linkmans = new HashSet<LinkMan>();
linkman(多的一方)
//配置一对多关系
/@ManyToOne(targetEntity = Customer.class)
//配置级联操作,一般级联不会配置到一的一方,太危险,会把所有对应的多都删除
@ManyToOne(targetEntity = Customer.class,cascade = CascadeType.ALL)
@JoinColumn(name = "lkm_cust_id",referencedColumnName = "cust_id")
private Customer customer;
2. 测试类
@Autowired
private ICustomerDao customerDao;
@Autowired
private ILinkmanDao linkmanDao;
//保存
@Test
public void testAdd() throws Exception{
Customer customer = new Customer();
customer.setCustName("test222");
LinkMan linkMan = new LinkMan();
linkMan.setLkmName("testl222");
linkMan.setCustomer(customer);
//只需要在维护外键的一方告诉关系即可保存维护外键
customerDao.save(customer);
linkmanDao.save(linkMan);
}
/**
* 级联删除
*/
@Test
@Transactional
@Rollback(value = false)
public void testCascadeDelete()throws Exception{
linkmanDao.delete(4l);
}
2. 多对多
1. 建立表之间的关联关系(实体类之间的关系)
SysUser
//配置多对多关系
@ManyToMany(targetEntity = SysRole.class,cascade = CascadeType.ALL)
@JoinTable(name = "user_role_rel",
joinColumns = {@JoinColumn(name = "user_id",referencedColumnName = "user_id")},
inverseJoinColumns = {@JoinColumn(name = "role_id",referencedColumnName = "role_id")}
)
private Set<SysRole> roles = new HashSet<>();
SysRole
//配置多对多关系,并放弃外键/表的维护
@ManyToMany(mappedBy = "roles")
private Set<SysUser> users = new HashSet<>();
2. 测试类
@Autowired
private ISysRoleDao roleDao;
@Autowired
private ISysUserDao userDao;
//保存
@Test
public void testAdd() throws Exception{
SysUser user = new SysUser();
user.setUserName("haha");
SysRole role = new SysRole();
role.setRoleName("hehe");
//在一方进行外键/表维护
user.getRoles().add(role);
userDao.save(user);
roleDao.save(role);
}
//删除,没有级联
@Test
@Transactional
@Rollback(value = false)
public void testDelete() throws Exception{
userDao.delete(2l);
}
3. 关于删除
* 有从表数据
1、在默认情况下,它会把外键字段置为null,然后删除主表数据。如果在数据库的表结构上,外键字段有非空约束,默认情况就会报错了。
2、如果配置了放弃维护关联关系的权利,则不能删除(与外键字段是否允许为null,没有关系)因为在删除时,它根本不会去更新从表的外键字段了。
3、如果还想删除,使用级联删除引用
* 没有从表数据引用:随便删
* 在多对多时候,级联删除最好不要配置,如果配了的话,如果数据之间有相互引用关系,可能会清空所有数据
对象导航查询
对象图导航检索方式是根据已经加载的对象,导航到他的关联对象。它利用类与类之间的关系来检索对象。
例如:我们通过ID查询方式查出一个user,可以调用user类中的getroles()方法来获取该用户的角色。
对象导航查询的使用要求是:两个对象之间必须存在关联关系。
简单理解:就是查询对象后通过.getXxx来调用有关联关系的属性
//对象导航查询
@Test
@Transactional
public void testObjectmap() throws Exception{
SysUser user = userDao.findOne(5l);
Set<SysRole> roles = user.getRoles();
System.out.println(roles);
}
Specification的多表查询
//创建的过程中,第一个参数为关联对象的属性名称,第二个参数为连接查询的方式(left,inner,right)
//JoinType.LEFT : 左外连接,JoinType.INNER:内连接,JoinType.RIGHT:右外连接
//使用Specification的多表查询
@Test
@Transactional
public void testSpec(){
SysUser user = userDao.findOne(new Specification<SysUser>() {
@Override
public Predicate toPredicate(Root<SysUser> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
Join<SysUser, SysRole> join = root.join("roles", JoinType.LEFT);
return criteriaBuilder.like(join.get("roleName").as(String.class), "he%");
}
});
Set<SysRole> roles = user.getRoles();
System.out.println(roles);
}
* roles,表示查询中当前类中的外键属性,后面的条件是对外连接表中条件的查询
* 也可以继续写root.xx,并对root条件限制,root代表的是本类的查询条件,join是连接表的插叙条件
Jpql的多表查询
在接口中重写方法,并使用@query注解
如:
@Query("select c from Customer c left outer join c.linkMans m where m.lkmId = 3")
List<Customer> getCustomerByLink();
版权声明:本文为qq_35472880原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。