JPA之对象导航查询

对象导航检索方式是根据已经加载的对象,导航到他的关联对象。它利用类与类之间的关系来检索对象。例如:我们通过ID查询方式查出一个客户,可以调用Customer类中的getLinkMans()方法来获取该客户的所有联系人。对象导航查询的使用要求是:两个对象之间必须存在关联关系。
对于客户和联系人的对应关系 参考 客户对象关系
查询一个客户,获取该客户下的所有联系人

package com.emon.demo;

import com.emon.demo.dao.CustomerDao;
import com.emon.demo.dao.LinkManDao;
import com.emon.demo.entity.Customer;
import com.emon.demo.entity.LinkMan;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Example;
import org.springframework.data.jpa.domain.Specification;

import javax.persistence.criteria.*;
import javax.transaction.Transactional;
import java.util.List;
import java.util.Set;

/**
 * 对象导航查询
 */
@SpringBootTest
public class ObjectQueryTest {
    @Autowired
    private CustomerDao customerDao;

    @Autowired
    private LinkManDao linkManDao;

    /**
查询一个客户,获取该客户下的所有联系人

     * 对象导航查询(一对多查询,)
     *          默认使用延迟加载的方式,调用get方法不会立即加载,而是在使用对象的时候才会使用
     *  修改配置,将延迟加载改为立即加载
     *      fetch,需要配置到多表映射关系的注解上面
     *
     *     #####重点  一对多的查询,在调用对象导航查询 查询多的一方数据时默认采用懒加载
     *              想使用立即加载 则 fetch = FetchType.EAGER,需要配置到多表映射关系的注解上面
     *
     */
    @Test
    @Transactional  // no Session 异常 采用事务的方式解决
    public void testQuery(){
        Customer cc = new Customer();
        cc.setCustId(1L);
        Customer customer = customerDao.findOne(Example.of(cc)).get();
        // 对象导航查询 通过get方法直接查询出linkMans
        Set<LinkMan> linmans = customer.getLinkMans();
        System.out.println("customer = " + customer);
        linmans.forEach(s -> System.out.println("s = " + s));
    }

    /**
查询一个联系人,获取该联系人的所有客户
     * 对象导航查询(一对多查询)
     *          查询一的一方的时候默认使用立即加载的方式,
     *      fetch = FetchType.LAZY,需要配置到多表映射关系的注解上面
     *
     */
    @Test
    @Transactional  // no Session 异常 采用事务的方式解决
    public void testQuery2(){
        LinkMan cc = new LinkMan();
        cc.setLkmId(1L);
        LinkMan linkMan = linkManDao.findOne(Example.of(cc)).get();
        // 对象导航查询 通过get方法直接查询出linkMans
        Customer customer = linkMan.getCustomer();
        System.out.println("customer = " + customer);
        // linmans.forEach(s -> System.out.println("s = " + s));
    }

    /**
     * Specification的多表查询
     */
    @Test
    public void testFind() {
        Specification<LinkMan> spec = new Specification<LinkMan>() {
            public Predicate toPredicate(Root<LinkMan> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                //Join代表链接查询,通过root对象获取
                //创建的过程中,第一个参数为关联对象的属性名称,第二个参数为连接查询的方式(left,inner,right)
                //JoinType.LEFT : 左外连接,JoinType.INNER:内连接,JoinType.RIGHT:右外连接
                Join<LinkMan, Customer> join = root.join("customer", JoinType.INNER);
                return cb.like(join.get("custName").as(String.class),"唐三");
            }
        };
        List<LinkMan> list = linkManDao.findAll(spec);
        for (LinkMan linkMan : list) {
            System.out.println(linkMan);
        }
    }

}

我们查询客户时,要不要把联系人查询出来?
分析:如果我们不查的话,在用的时候还要自己写代码,调用方法去查询。如果我们查出来的,不使用时又会白白的浪费了服务器内存。
解决:采用延迟加载的思想。通过配置的方式来设定当我们在需要使用时,发起真正的查询。
配置方式:

	/**
	 * 在客户对象的@OneToMany注解中添加fetch属性
	 * 		FetchType.EAGER	:立即加载
	 * 		FetchType.LAZY	:延迟加载
	 */
	@OneToMany(mappedBy="customer",fetch=FetchType.EAGER)
	private Set<LinkMan> linkMans = new HashSet<>(0);

问题2:我们查询联系人时,要不要把客户查询出来?

分析:例如:查询联系人详情时,肯定会看看该联系人的所属客户。如果我们不查的话,在用的时候还要自己写代码,调用方法去查询。如果我们查出来的话,一个对象不会消耗太多的内存。而且多数情况下我们都是要使用的。

解决: 采用立即加载的思想。通过配置的方式来设定,只要查询从表实体,就把主表实体对象同时查出来

配置方式

	/**
	 * 在联系人对象的@ManyToOne注解中添加fetch属性
	 * 		FetchType.EAGER	:立即加载
	 * 		FetchType.LAZY	:延迟加载
	 */
	@ManyToOne(targetEntity=Customer.class,fetch=FetchType.EAGER)
	@JoinColumn(name="cst_lkm_id",referencedColumnName="cust_id")
	private Customer customer;

点击连接查看源码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值