1 关联映射操作
1.1 多表之间的关系和操作多表的操作步骤
1.1.1 @OneToMany:
作用:建立一对多的关系映射 属性: targetEntityClass:指定多的多方的类的字节码 mappedBy:指定从表实体类中引用主表对象的名称。 cascade:指定要使用的级联操作 fetch:指定是否采用延迟加载 orphanRemoval:是否使用孤儿删除
1.1.2 @ManyToOne
作用:建立多对一的关系 属性: targetEntityClass:指定一的一方实体类字节码 cascade:指定要使用的级联操作 fetch:指定是否采用延迟加载 optional:关联是否可选。如果设置为false,则必须始终存在非空关系。
1.1.3 @JoinColumn
作用:用于定义主键字段和外键字段的对应关系。 属性: name:指定外键字段的名称 referencedColumnName:指定引用主表的主键字段名称 unique:是否唯一。默认值不唯一 nullable:是否允许为空。默认值允许。 insertable:是否允许插入。默认值允许。 updatable:是否允许更新。默认值允许。 columnDefinition:列的定义信息。
表关系 一对一:和一对多同理,就是看哪一方要维护外键.谁维护都行,主要是分清楚谁是主表,谁是从表 一对多: 一的一方:主表 多的一方:从表 外键:需要再从表上新建一列作为外键,他的取值来源于主表的主键 多对多: 中间表:中间表中最少应该由两个字段组成,这两个字段做为外键指向两张表的主键,又组成了联合主键 讲师对学员:一对多关系 实体类中的关系 包含关系:可以通过实体类中的包含关系描述表关系 继承关系 分析步骤 1.明确表关系 2.确定表关系(描述 外键|中间表) 3.编写实体类,再实体类中描述表关系(包含关系) 4.配置映射关系
1.2 一对多的关联关系
i.一对多操作 案例:客户和联系人的案例(一对多关系) 客户:一家公司 联系人:这家公司的员工 一个客户可以具有多个联系人 一个联系人从属于一家公司 分析步骤 1.明确表关系 一对多关系 2.确定表关系(描述 外键|中间表) 主表:客户表 从表:联系人表 * 再从表上添加外键 3.编写实体类,再实体类中描述表关系(包含关系) 客户:再客户的实体类中包含一个联系人的集合 联系人:在联系人的实体类中包含一个客户的对象 4.配置映射关系 * 使用jpa注解配置一对多映射关系 级联: 操作一个对象的同时操作他的关联对象 级联操作: 1.需要区分操作主体 2.需要在操作主体的实体类上,添加级联属性(需要添加到多表映射关系的注解上) 3.cascade(配置级联) 级联添加, 案例:当我保存一个客户的同时保存联系人 级联删除 案例:当我删除一个客户的同时删除此客户的所有联系人
2、实体类
package cn.oldlu.domain; import javax.persistence.*; import java.util.HashSet; import java.util.Set; /** * 1.实体类和表的映射关系 * @Eitity * @Table * 2.类中属性和表中字段的映射关系 * @Id * @GeneratedValue * @Column */ @Entity @Table(name="cst_customer") public class Customer { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name="cust_id") private Long custId; @Column(name="cust_address") private String custAddress; @Column(name="cust_industry") private String custIndustry; @Column(name="cust_level") private String custLevel; @Column(name="cust_name") private String custName; @Column(name="cust_phone") private String custPhone; @Column(name="cust_source") private String custSource; //配置客户和联系人之间的关系(一对多关系) /** * 使用注解的形式配置多表关系 * 1.声明关系 * @OneToMany : 配置一对多关系 * targetEntity :对方对象的字节码对象 * 2.配置外键(中间表) * @JoinColumn : 配置外键 * name:外键字段名称 一般有这个的时候mysql会自动创建字段,不需要重复定义 * referencedColumnName:参照的主表的主键字段名称 * * * 在客户实体类上(一的一方)添加了外键了配置,所以对于客户而言,也具备了维护外键的作用 * */ // @OneToMany(targetEntity = LinkMan.class) // @JoinColumn(name = "lkm_cust_id",referencedColumnName = "cust_id") /** * 放弃外键维护权 * mappedBy:对方配置关系的属性名称\ * cascade : 配置级联(可以配置到设置多表的映射关系的注解上) * CascadeType.all : 所有 * MERGE :更新 * PERSIST :保存 * REMOVE :删除 * * fetch : 配置关联对象的加载方式 * EAGER :立即加载 * LAZY :延迟加载 */ @OneToMany(mappedBy = "customer",cascade = CascadeType.ALL) private Set<LinkMan> linkMans = new HashSet<>(); public Long getCustId() { return custId; } public void setCustId(Long custId) { this.custId = custId; } public String getCustAddress() { return custAddress; } public void setCustAddress(String custAddress) { this.custAddress = custAddress; } public String getCustIndustry() { return custIndustry; } public void setCustIndustry(String custIndustry) { this.custIndustry = custIndustry; } public String getCustLevel() { return custLevel; } public void setCustLevel(String custLevel) { this.custLevel = custLevel; } public String getCustName() { return custName; } public void setCustName(String custName) { this.custName = custName; } public String getCustPhone() { return custPhone; } public void setCustPhone(String custPhone) { this.custPhone = custPhone; } public String getCustSource() { return custSource; } public void setCustSource(String custSource) { this.custSource = custSource; } public Set<LinkMan> getLinkMans() { return linkMans; } public void setLinkMans(Set<LinkMan> linkMans) { this.linkMans = linkMans; } @Override public String toString() { return "Customer{" + "custId=" + custId + ", custAddress='" + custAddress + '\'' + ", custIndustry='" + custIndustry + '\'' + ", custLevel='" + custLevel + '\'' + ", custName='" + custName + '\'' + ", custPhone='" + custPhone + '\'' + ", custSource='" + custSource + '\'' + '}'; } }
package cn.oldlu.domain; import javax.persistence.*; @Entity @Table(name = "cst_linkman") public class LinkMan { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "lkm_id") private Long lkmId; //联系人编号(主键) @Column(name = "lkm_name") private String lkmName;//联系人姓名 @Column(name = "lkm_gender") private String lkmGender;//联系人性别 @Column(name = "lkm_phone") private String lkmPhone;//联系人办公电话 @Column(name = "lkm_mobile") private String lkmMobile;//联系人手机 @Column(name = "lkm_email") private String lkmEmail;//联系人邮箱 @Column(name = "lkm_position") private String lkmPosition;//联系人职位 @Column(name = "lkm_memo") private String lkmMemo;//联系人备注 /** * 配置联系人到客户的多对一关系 * 使用注解的形式配置多对一关系 * 1.配置表关系 * @ManyToOne : 配置多对一关系 * targetEntity:对方的实体类字节码 * 2.配置外键(中间表) * * * 配置外键的过程,配置到了多的一方,就会在多的一方维护外键 * */ @ManyToOne(targetEntity = Customer.class,fetch = FetchType.LAZY) @JoinColumn(name = "lkm_cust_id",referencedColumnName = "cust_id") private Customer customer; public Long getLkmId() { return lkmId; } public void setLkmId(Long lkmId) { this.lkmId = lkmId; } public String getLkmName() { return lkmName; } public void setLkmName(String lkmName) { this.lkmName = lkmName; } public String getLkmGender() { return lkmGender; } public void setLkmGender(String lkmGender) { this.lkmGender = lkmGender; } public String getLkmPhone() { return lkmPhone; } public void setLkmPhone(String lkmPhone) { this.lkmPhone = lkmPhone; } public String getLkmMobile() { return lkmMobile; } public void setLkmMobile(String lkmMobile) { this.lkmMobile = lkmMobile; } public String getLkmEmail() { return lkmEmail; } public void setLkmEmail(String lkmEmail) { this.lkmEmail = lkmEmail; } public String getLkmPosition() { return lkmPosition; } public void setLkmPosition(String lkmPosition) { this.lkmPosition = lkmPosition; } public String getLkmMemo() { return lkmMemo; } public void setLkmMemo(String lkmMemo) { this.lkmMemo = lkmMemo; } public Customer getCustomer() { return customer; } public void setCustomer(Customer customer) { this.customer = customer; } @Override public String toString() { return "LinkMan{" + "lkmId=" + lkmId + ", lkmName='" + lkmName + '\'' + ", lkmGender='" + lkmGender + '\'' + ", lkmPhone='" + lkmPhone + '\'' + ", lkmMobile='" + lkmMobile + '\'' + ", lkmEmail='" + lkmEmail + '\'' + ", lkmPosition='" + lkmPosition + '\'' + ", lkmMemo='" + lkmMemo + '\'' + '}'; } }
3、dao层接口编写
package cn.oldlu.dao; import cn.oldlu.domain.Customer; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import java.util.List; /** * 符合SpringDataJpa的dao层接口规范 * JpaRepository<操作的实体类类型,实体类中主键属性的类型> * * 封装了基本CRUD操作 * JpaSpecificationExecutor<操作的实体类类型> * * 封装了复杂查询(分页) */ public interface CustomerDao extends JpaRepository<Customer,Long> ,JpaSpecificationExecutor<Customer> { }
package cn.oldlu.dao; import cn.oldlu.domain.LinkMan; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; /** * 联系人的dao接口 */ public interface LinkManDao extends JpaRepository<LinkMan,Long>, JpaSpecificationExecutor<LinkMan> { }
4、测试查询
package cn.oldlu.test; import cn.oldlu.dao.CustomerDao; import cn.oldlu.dao.LinkManDao; import cn.oldlu.domain.Customer; import cn.oldlu.domain.LinkMan; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.transaction.annotation.Transactional; import java.util.Set; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath:applicationContext.xml") public class ObjectQueryTest { @Autowired private CustomerDao customerDao; @Autowired private LinkManDao linkManDao; //could not initialize proxy - no Session //测试对象导航查询(查询一个对象的时候,通过此对象查询所有的关联对象) @Test @Transactional // 解决在java代码中的no session问题 public void testQuery1() { //查询id为1的客户 Customer customer = customerDao.getOne(1l); //对象导航查询,此客户下的所有联系人 Set<LinkMan> linkMans = customer.getLinkMans(); for (LinkMan linkMan : linkMans) { System.out.println(linkMan); } } /** * 对象导航查询: * 默认使用的是延迟加载的形式查询的 * 调用get方法并不会立即发送查询,而是在使用关联对象的时候才会差和讯 * 延迟加载! * 修改配置,将延迟加载改为立即加载 * fetch,需要配置到多表映射关系的注解上 * */ @Test @Transactional // 解决在java代码中的no session问题 public void testQuery2() { //查询id为1的客户 Customer customer = customerDao.findOne(1l); //对象导航查询,此客户下的所有联系人 Set<LinkMan> linkMans = customer.getLinkMans(); System.out.println(linkMans.size()); } /** * 从联系人对象导航查询他的所属客户 * * 默认 : 立即加载 * 延迟加载: * */ @Test @Transactional // 解决在java代码中的no session问题 public void testQuery3() { LinkMan linkMan = linkManDao.findOne(2l); //对象导航查询所属的客户 Customer customer = linkMan.getCustomer(); System.out.println(customer); } }
5.测试删改查
package cn.oldlu.test; import cn.oldlu.dao.CustomerDao; import cn.oldlu.dao.LinkManDao; import cn.oldlu.domain.Customer; import cn.oldlu.domain.LinkMan; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.annotation.Rollback; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.transaction.annotation.Transactional; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath:applicationContext.xml") public class OneToManyTest { @Autowired private CustomerDao customerDao; @Autowired private LinkManDao linkManDao; /** * 保存一个客户,保存一个联系人 * 效果:客户和联系人作为独立的数据保存到数据库中 * 联系人的外键为空 * 原因? * 实体类中没有配置关系 */ @Test @Transactional //配置事务 @Rollback(false) //不自动回滚 public void testAdd() { //创建一个客户,创建一个联系人 Customer customer = new Customer(); customer.setCustName("百度"); LinkMan linkMan = new LinkMan(); linkMan.setLkmName("小李"); /** * 配置了客户到联系人的关系 * 从客户的角度上:发送两条insert语句,发送一条更新语句更新数据库(更新外键) * 由于我们配置了客户到联系人的关系:客户可以对外键进行维护 */ customer.getLinkMans().add(linkMan); customerDao.save(customer); linkManDao.save(linkMan); } @Test @Transactional //配置事务 @Rollback(false) //不自动回滚 public void testAdd1() { //创建一个客户,创建一个联系人 Customer customer = new Customer(); customer.setCustName("百度"); LinkMan linkMan = new LinkMan(); linkMan.setLkmName("小李"); /** * 配置联系人到客户的关系(多对一) * 只发送了两条insert语句 * 由于配置了联系人到客户的映射关系(多对一) * * */ linkMan.setCustomer(customer); customerDao.save(customer); linkManDao.save(linkMan); } /** * 会有一条多余的update语句 * * 由于一的一方可以维护外键:会发送update语句 * * 解决此问题:只需要在一的一方放弃维护权即可 * */ @Test @Transactional //配置事务 @Rollback(false) //不自动回滚 public void testAdd2() { //创建一个客户,创建一个联系人 Customer customer = new Customer(); customer.setCustName("百度"); LinkMan linkMan = new LinkMan(); linkMan.setLkmName("小李"); linkMan.setCustomer(customer);//由于配置了多的一方到一的一方的关联关系(当保存的时候,就已经对外键赋值) customer.getLinkMans().add(linkMan);//由于配置了一的一方到多的一方的关联关系(发送一条update语句) customerDao.save(customer); linkManDao.save(linkMan); } /** * 级联添加:保存一个客户的同时,保存客户的所有联系人 * 需要在操作主体的实体类上,配置casacde属性 */ @Test @Transactional //配置事务 @Rollback(false) //不自动回滚 public void testCascadeAdd() { Customer customer = new Customer(); customer.setCustName("百度1"); LinkMan linkMan = new LinkMan(); linkMan.setLkmName("小李1"); linkMan.setCustomer(customer); customer.getLinkMans().add(linkMan); customerDao.save(customer); } /** * 级联删除: * 删除1号客户的同时,删除1号客户的所有联系人 */ @Test @Transactional //配置事务 @Rollback(false) //不自动回滚 public void testCascadeRemove() { //1.查询1号客户 Customer customer = customerDao.findOne(1l); //2.删除1号客户 customerDao.delete(customer); } }
1.3 多对多的关联关系
注解说明:
1.3.1 @ManyToMany
作用:用于映射多对多关系 属性: cascade:配置级联操作。 fetch:配置是否采用延迟加载。 targetEntity:配置目标的实体类。映射多对多的时候不用写。
1.3.2 @JoinTable
作用:针对中间表的配置 属性: nam:配置中间表的名称 joinColumns:中间表的外键字段关联当前实体类所对应表的主键字段 inverseJoinColumn:中间表的外键字段关联对方表的主键字段
1.3.3 @JoinColumn
作用:用于定义主键字段和外键字段的对应关系。 属性: name:指定外键字段的名称 referencedColumnName:指定引用主表的主键字段名称 unique:是否唯一。默认值不唯一 nullable:是否允许为空。默认值允许。 insertable:是否允许插入。默认值允许。 updatable:是否允许更新。默认值允许。 columnDefinition:列的定义信息。
ii.多对多操作 案例:用户和角色(多对多关系) 用户: 角色: 分析步骤 1.明确表关系 多对多关系 2.确定表关系(描述 外键|中间表) 中间间表 3.编写实体类,再实体类中描述表关系(包含关系) 用户:包含角色的集合 角色:包含用户的集合 4.配置映射关系 iii.多表的查询 1.对象导航查询 查询一个对象的同时,通过此对象查询他的关联对象 案例:客户和联系人 从一方查询多方 * 默认:使用延迟加载(****) 从多方查询一方 * 默认:使用立即加载
6、实体类
package cn.oldlu.domain; import javax.persistence.*; import java.util.HashSet; import java.util.Set; @Entity @Table(name = "sys_role") public class Role { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "role_id") private Long roleId; @Column(name = "role_name") private String roleName; //配置多对多 @ManyToMany(mappedBy = "roles") //配置多表关系 private Set<User> users = new HashSet<>(); public Long getRoleId() { return roleId; } public void setRoleId(Long roleId) { this.roleId = roleId; } public String getRoleName() { return roleName; } public void setRoleName(String roleName) { this.roleName = roleName; } public Set<User> getUsers() { return users; } public void setUsers(Set<User> users) { this.users = users; } }
package cn.oldlu.domain; import javax.persistence.*; import java.util.HashSet; import java.util.Set; @Entity @Table(name = "sys_user") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name="user_id") private Long userId; @Column(name="user_name") private String userName; @Column(name="age") private Integer age; /** * 配置用户到角色的多对多关系 * 配置多对多的映射关系 * 1.声明表关系的配置 * @ManyToMany(targetEntity = Role.class) //多对多 * targetEntity:代表对方的实体类字节码 * 2.配置中间表(包含两个外键) * @JoinTable * name : 中间表的名称 * joinColumns:配置当前对象在中间表的外键 * @JoinColumn的数组 * name:外键名 * referencedColumnName:参照的主表的主键名 * inverseJoinColumns:配置对方对象在中间表的外键 */ @ManyToMany(targetEntity = Role.class,cascade = CascadeType.ALL) @JoinTable(name = "sys_user_role", //joinColumns,当前对象在中间表中的外键 joinColumns = {@JoinColumn(name = "sys_user_id",referencedColumnName = "user_id")}, //inverseJoinColumns,对方对象在中间表的外键 inverseJoinColumns = {@JoinColumn(name = "sys_role_id",referencedColumnName = "role_id")} ) private Set<Role> roles = new HashSet<>(); public Long getUserId() { return userId; } public void setUserId(Long userId) { this.userId = userId; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Set<Role> getRoles() { return roles; } public void setRoles(Set<Role> roles) { this.roles = roles; } }
7、dao层接口
package cn.oldlu.dao; import cn.oldlu.domain.Role; import cn.oldlu.domain.User; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; public interface RoleDao extends JpaRepository<Role,Long> ,JpaSpecificationExecutor<Role> { } }
package cn.oldlu.dao; import cn.oldlu.domain.User; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; public interface UserDao extends JpaRepository<User,Long> ,JpaSpecificationExecutor<User> { }
8、测试
package cn.oldlu.test; import cn.oldlu.dao.RoleDao; import cn.oldlu.dao.UserDao; import cn.oldlu.domain.Role; import cn.oldlu.domain.User; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.annotation.Rollback; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.transaction.annotation.Transactional; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath:applicationContext.xml") public class ManyToManyTest { @Autowired private UserDao userDao; @Autowired private RoleDao roleDao; /** * 保存一个用户,保存一个角色 * * 多对多放弃维护权:被动的一方放弃 */ @Test @Transactional @Rollback(false) public void testAdd() { User user = new User(); user.setUserName("小李"); Role role = new Role(); role.setRoleName("java程序员"); //配置用户到角色关系,可以对中间表中的数据进行维护 1-1 user.getRoles().add(role); //配置角色到用户的关系,可以对中间表的数据进行维护 1-1 role.getUsers().add(user); userDao.save(user); roleDao.save(role); } //测试级联添加(保存一个用户的同时保存用户的关联角色) @Test @Transactional @Rollback(false) public void testCasCadeAdd() { User user = new User(); user.setUserName("小李"); Role role = new Role(); role.setRoleName("java程序员"); //配置用户到角色关系,可以对中间表中的数据进行维护 1-1 user.getRoles().add(role); //配置角色到用户的关系,可以对中间表的数据进行维护 1-1 role.getUsers().add(user); userDao.save(user); } /** * 案例:删除id为1的用户,同时删除他的关联对象 */ @Test @Transactional @Rollback(false) public void testCasCadeRemove() { //查询1号用户 User user = userDao.findOne(1l); //删除1号用户 userDao.delete(user); } }
2 对象导航查询
对象图导航检索方式是根据已经加载的对象,导航到他的关联对象。它利用类与类之间的关系来检索对象。例如:我们通过ID查询方式查出一个客户,可以调用Customer类中的getLinkMans()方法来获取该客户的所有联系人。对象导航查询的使用要求是:两个对象之间必须存在关联关系。
查询一个客户,获取该客户下的所有联系人
@Autowired private CustomerDao customerDao; @Test //由于是在java代码中测试,为了解决no session问题,将操作配置到同一个事务中 @Transactional public void testFind() { Customer customer = customerDao.findOne(5l); Set<LinkMan> linkMans = customer.getLinkMans();//对象导航查询 for(LinkMan linkMan : linkMans) { System.out.println(linkMan); } }
查询一个联系人,获取该联系人的所有客户
@Autowired private LinkManDao linkManDao; @Test public void testFind() { LinkMan linkMan = linkManDao.findOne(4l); Customer customer = linkMan.getCustomer(); //对象导航查询 System.out.println(customer); }
对象导航查询的问题分析
问题1:我们查询客户时,要不要把联系人查询出来?
分析:如果我们不查的话,在用的时候还要自己写代码,调用方法去查询。如果我们查出来的,不使用时又会白白的浪费了服务器内存。
解决:采用延迟加载的思想。通过配置的方式来设定当我们在需要使用时,发起真正的查询。
配置方式:
/** * 在客户对象的@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;
3 Specification的多表联合查询
/** * 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),"老陆1"); } }; List<LinkMan> list = linkManDao.findAll(spec); for (LinkMan linkMan : list) { System.out.println(linkMan); } }
4 SQL方式查询
@Query(value = "SELECT\n" + "\tt_internet_scheduling.*\n" + "FROM\n" + "\tt_internet_member\n" + "\tRIGHT JOIN t_internet_scheduling ON t_internet_member.schedule_id = t_internet_scheduling.id \n" + "WHERE\n" + "\t( CASE WHEN :phone IS NOT NULL THEN phone= :phone ELSE 1 <> 1 END " + "OR CASE WHEN :idNum IS NOT NULL THEN id_num= :idNum ELSE 1 <> 1 END)AND CASE WHEN :caseNo IS NOT NULL THEN case_no like :caseNo ELSE 1 = 1 END\n" + "AND CASE WHEN :isOpen IS NOT NULL THEN is_open= :isOpen ELSE 1 = 1 END ORDER BY start_time DESC\n ", countQuery = "SELECT COUNT(*) FROM t_internet_member\n" + " RIGHT JOIN t_internet_scheduling ON t_internet_member.schedule_id = t_internet_scheduling.id \n" + " WHERE\n" + " ( CASE WHEN :phone IS NOT NULL THEN phone= :phone ELSE 1 <> 1 END \n" + " OR CASE WHEN :idNum IS NOT NULL THEN id_num= :idNum ELSE 1 <> 1 END)AND CASE WHEN :caseNo IS NOT NULL THEN case_no like :caseNo ELSE 1 = 1 END\n" + " AND CASE WHEN :isOpen IS NOT NULL THEN is_open= :isOpen ELSE 1 = 1 END ORDER BY start_time DESC" , nativeQuery = true) Page<InternetScheduling> findByIdCardAndPhone(@Param("idNum") String idNum, @Param("phone") String phone, @Param("caseNo") String caseNo,@Param("isOpen") String isOpen,Pageable pageable);