Spring Data--多表查询 (二)

一、多表查询

1、方式一(本地SQL):

1)实体类

@Entity
@Table(name = "gateway_route")
@Data
@GenericGenerator(name = "jpa-uuid", strategy = "uuid")
public class GatewayRoute implements Serializable {
    /**
     * 路由的Id
     */
    @Id
    @GeneratedValue(generator = "jpa-uuid")
    @Column(length = 32)
    private String id;
    /**
     * 路由规则转发的目标uri
     */
    private String uri;
    /**
     * 路由执行的顺序
     */
    @Column(name="route_order")
    private Integer orders = 0;
}

@Entity
@Table(name = "gateway_predicate")
@Data
public class GatewayPredicate implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;
    /**
     * 断言对应的Name
     */
    private String name;
    @Column(name="route_id")
    private  String routeId;
}

2)无条件连接分页查询

@Repository
public interface GatewayRouteRepository extends JpaRepository , JpaSpecificationExecutor {
    @Query(nativeQuery = true, value ="SELECT r.id,r.route_order,p.`name` FROM gateway_route r,gateway_predicate p WHERE r.id=p.route_id ")
    Page getGatewayRouteAndGatewayPredicate(Pageable pageable);
}
测试:
        Page list = gatewayRouteRepository.getGatewayRouteAndGatewayPredicate(PageRequest.of(0, 10));
        log.info(JSON.toJSONString(list));
        log.info(list.getTotalElements()+"");

2)无条件连接查询

    @Query(nativeQuery = true, value = "SELECT r.id,r.route_order,p.`name` FROM gateway_route r,gateway_predicate p WHERE r.id=p.route_id ")
    List getGatewayRouteAndGatewayPredicate();
测试:
        List list = gatewayRouteRepository.getGatewayRouteAndGatewayPredicate();
        log.info(JSON.toJSONString(list));
SQL:
Hibernate: SELECT r.id,r.route_order,p.`name` FROM gateway_route r,gateway_predicate p WHERE r.id=p.route_id 
返回数据:
[["402881ee679c888301679c889b1f0000",0,"predicate"]]

2)条件连接查询

 @Query(nativeQuery = true, value = "SELECT r.id,r.route_order,p.`name` FROM gateway_route r,gateway_predicate p WHERE r.id=p.route_id AND r.id=?1")
    List getGatewayRouteAndGatewayPredicate(String id);
测试:
        List list = gatewayRouteRepository.getGatewayRouteAndGatewayPredicate("402881ee679c888301679c889b1f0000");
        log.info(JSON.toJSONString(list));
SQL:
Hibernate: SELECT r.id,r.route_order,p.`name` FROM gateway_route r,gateway_predicate p WHERE r.id=p.route_id AND r.id=?
返回数据:
[["402881ee679c888301679c889b1f0000",0,"predicate"]]

2、方式二(JPA SQL):

@ManyToOne
@JoinColumn
@OneToMany
@ManyToMany
注解的使用:
1)实体类

@Entity
@Table(name = "gateway_route")
@Data
@GenericGenerator(name = "jpa-uuid", strategy = "uuid")
public class GatewayRoute implements Serializable {
    /**
     * 路由的Id
     */
    @Id
    @GeneratedValue(generator = "jpa-uuid")
    @Column(length = 32)
    private String id;
    /**
     * 路由规则转发的目标uri
     */
    private String uri;
    /**
     * 路由执行的顺序
     */
    @Column(name="route_order")
    private Integer orders = 0;

    /**
     * 路由断言集合配置
     * 级联保存、更新、删除、刷新;延迟加载。
     * 拥有mappedBy注解的实体类为关系被维护端
     */
      @OneToMany(cascade= CascadeType.ALL,fetch=FetchType.EAGER)
    @JoinColumn(name="route_id")
    private Set predicates=new HashSet<>();
}

@Entity
@Table(name = "gateway_predicate")
@Data
public class GatewayPredicate implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;
    /**
     * 断言对应的Name
     */
    private String name;
}

2)一对多查询

   @Query("select r,p from GatewayRoute r join r.predicates p ")
    List getGatewayRouteAndGatewayPredicate();
测试:
        List list = gatewayRouteRepository.getGatewayRouteAndGatewayPredicate();
        log.info(JSON.toJSONString(list));
SQL:
select gatewayrou0_.id as id1_2_0_, predicates1_.id as id1_0_1_, gatewayrou0_.route_order as route_or2_2_0_, gatewayrou0_.uri as uri3_2_0_, predicates1_.name as name2_0_1_ from gateway_route gatewayrou0_ inner join gateway_predicate predicates1_ on gatewayrou0_.id=predicates1_.route_id
返回数据:
[[{"id":"402881ee679c888301679c889b1f0000","orders":0,"predicates":[{"id":2,"name":"predicate"}],"uri":"http://www.baidu.com"},{"$ref":"$[0].null.predicates[0]"}]]

2)多对多查询
admin.java

@Data
@Table(name = "sys_admin")
@EntityListeners(AuditingEntityListener.class)
@org.hibernate.annotations.Table(appliesTo = "sys_admin", comment = "系统管理员表")
@Entity
public class Admin extends BaseEntity implements Serializable {
    @Id
    @GeneratedValue
    private Long id;
    @Column(nullable = false, columnDefinition = "varchar(63) comment '管理员名称'")
    private String username;
    @Column(nullable = false, columnDefinition = "varchar(63) comment '管理员密码'")
    private String password;
    @Column(length = 63, columnDefinition = "varchar(63) comment '最后一次登录IP'")
    private String lastLoginIp;
    @Column(columnDefinition = "datetime comment '最后一次登录时间'")
    private LocalDateTime lastLoginTime;
    @Column(columnDefinition = "varchar(63) comment '头像图片'")
    private String avatar;
    /**
     * 多对多关系(主类为:admin, 属性为:role 中间表为:sys_admin_role)
     * 这样就建立了表与表之间的关系
     * @描  述: 关闭懒加载fetch=FetchType.EAGER
     * inverseJoinColumns属性与joinColumns属性类似,它保存的是保存关系的另一个外键字段。
     * joinColumns是主操作表的中间表列
     * sys_admin_role 中间表名称
     * 而inverseJoinColumns是副操作表的中间表列。
     *  * @参  数: ${tags}
     *  * @返  回: ${return_type}
     */
    @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    @JoinTable(name = "sys_admin_role", joinColumns = {
            @JoinColumn(name = "admin_id", referencedColumnName = "id")},
            inverseJoinColumns = {@JoinColumn(name = "role_id", referencedColumnName = "id")})
    private Set roles=new HashSet<>();
}

Role.java

@Data
@javax.persistence.Table(name = "sys_role")
@EntityListeners(AuditingEntityListener.class)
@Table(appliesTo = "sys_role", comment = "角色表")    //此注解主要为了添加表注释
@Entity
@DynamicUpdate
@JsonIgnoreProperties(value={"admins"})
public class Role extends BaseEntity implements Serializable {
    @Id
    @GeneratedValue
    private Long id;
    @Column(nullable = false, columnDefinition = "varchar(63) comment '角色名称'")
    private String roleName;
    @Column(columnDefinition = "varchar(63) comment '角色描述'")
    private String description;
    @Column(columnDefinition = "bit comment '是否启用'")
    private Boolean enabled;

    /**
     * 一个角色有多个权限
     */
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    @JoinColumn(name = "roleId", referencedColumnName = "id")
    private Set permissions;
    /**
     * @描 述: @ManyToMany 注释表示Student是多对多关系的一边,
     * mappedBy 属性定义了roles为双向关系的维护端,一定在Admin类中有定义
     * mappedBy:所填内容必为本类在另一方的字段名。
     * 表示:本类放弃控制关联关系,所有对关联关系的控制,
     * 如:建立、解除与另一方的关系,都由对方控制,本类不管。
     * CascadeType.PERSIST级联保存
     * CascadeType.MERGE级联更新
     * CascadeType.REFRESH级联刷新
     * CascadeType.REMOVE级联删除
     * fetch = FetchType.EAGER,关闭懒加载会死循环
     * fetch = FetchType.LAZY, 异常 failed to lazily initialize a collection of role
     * 无限循环需加两个注解:
     *  @Transient
     *  @JSONField(serialize = false)
     */
    @ManyToMany(mappedBy = "roles", fetch = FetchType.LAZY ,cascade = { CascadeType.PERSIST, CascadeType.MERGE })
    @Transient
    @JSONField(serialize = false)
    private Set admins=new HashSet<>();
}


数据添加测试:(添加中间表数据)
一定要在控制类方面添加数据。
如果使用被控类添加,中间表数据为空。

    @Test
    public void updateAdmin(){
        //给Admin管理员添加角色
        Admin admin=new Admin();
        admin.setId(18L);
        admin.setUsername("admin");
        admin.setPassword("123456");
        Set roles=new HashSet<>();
        //添加角色与关系只可以admin一方
        Role role=new Role();
        role.setId(19L);
        role.setRoleName("超级管理员");
        roles.add(role);
        admin.setRoles(roles);
        adminRepository.saveAndFlush(admin);
    }

结果:


中间表结果

中间表结果
    @Test
    public void findByUsername() {
        //为And条件
        Admin admin = new Admin();
        admin.setUsername("admin");
        admin.setPassword("123456");
        Example example = Example.of(admin);
        List admins = adminRepository.findAll(example);
        String str = JSONArray.toJSONString(admins);
        log.info(str);
    }

你可能感兴趣的:(Spring Data--多表查询 (二))