JPA 之 多表聯合查詢

Ivy Huang發表於2020-08-18

有兩種情況:一種是返回所有表的所有資料;一種是隻返回想要的部分資料;

兩種情況主要區別在於vo類和dao層。

vo類的區別:需要返回什麼就放什麼,如果是返回全部表的全部資料,則放兩個實體類,並表清表與表之間的關聯。如果是返回部分欄位,就放部分欄位。
dao層的區別:select new…()… -----這個括號裡寫要查詢的東西。查全部表就寫表名或者簡寫的表名;只查部分資料就寫要返回的資料如表名.欄位,順序必須與Vo類中的建構函式中的順序一致。

第一種:返回所有表的全部資料

表結構:
1. 訂單表:orders

Field              Type                         Comment
id           int(11) unsigned NOT NULL          訂單編號
number       varchar(30) NOT NULL               訂單號碼
pay_time     datetime NOT NULL                  支付時間
members_id   int(11) unsigned NOT NULL          會員編號
vip_id       int(11) unsigned NOT NULL          會員套餐編號
del          smallint(11) unsigned NOT NULL     是否可用:0-否,1-是
2. 會員套餐詳情表:vip

Field              Type                           Comment
id             int(11) unsigned NOT NULL         會員套餐編號
name           varchar(30) NOT NULL              會員套餐名稱
price          int(11) unsigned NOT NULL         套餐價格
del            smallint(11) unsigned NOT NULL    是否刪除:0-否,1-是
兩個實體類:
@Data
@Entity
@Table(name = "orders")  
public class Orders implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;  //訂單編號

    @NotNull(message = "訂單號碼不能為空")
    @Column(name = "number")
    private String number; // 訂單號碼

    @NotNull(message = "支付時間不能為空")
    @Column(name = "pay_time")
    private Date payTime;  //訂單支付時間

    @NotNull(message = "會員編號不能為空")
    @Column(name = "members_id")
    private Integer membersId;  //會員編號

    @NotNull(message = "會員套餐不能為空")
    @Column(name = "vip_id")
    private Integer vipId;  //購買的會員套餐編號

    private Integer del; //是否可用:0-否,1-是
}
新建Vo類:接收多表關聯返回結集,該類中放你返回的資料,需要什麼放什麼(裡面描述兩表關係)
@Data
public class VipOrdersVo implements Serializable {

    private Vip vip;  //引入表物件

    private Orders orders;//引入表物件

    public VipOrders() {
    }
    
     public VipOrders(Vip vip, Orders orders) {  //必須有建構函式
        this.vip = vip;
        this.orders = orders;
    }
 
    public VipOrders(Vip vip){  //在兩者之間建立聯絡
       Orders orders = new Orders();  
       this.orders = orders;
       this.vip = vip;
    }
    
    public VipOrders(Orders orders){  //在兩者之間建立聯絡
        Vip vip = new Vip();  
        this.vip =vip;
        this.orders= orders;
    }
}
controller層:
 @GetMapping("/list")
  public Result ordersList(@RequestParam Integer pageNo, @RequestParam Integer pageSize){
        return ordersService.getOrdersList(pageNo,pageSize);
    }
service實現層:
Service介面中方法:返回你定義的Vo泛型的list就行

@Override
    public Result getOrdersList(Integer pageNo, Integer pageSize) {
        
            Pageable pageable = PageRequest.of(pageNo,pageSize);
            List<VipOrdersVo> vipOrdersVos = ordersDao.findVipOrdersVo(pageable);

            return ResultUtil.success(vipOrdersVos);
    }
Dao層:
@Repository
public interface OrdersDao extends JpaRepository<Orders, Integer> {

   @Query(value = "SELECT new com.cvc.livingcircle.vo.Orders.VipOrdersVo(v,o) from Vip v,Orders o where v.id = o.vipId")
    List<VipOrders> findVipOrdersVo(Pageable pageable);
}

注意:注意:new 絕對不能少,後面最好跟全限定類名(不寫有可能找不到這個類),還有new com.cvc.livingcircle.vo.XXXVo( )...括號裡面寫你要查的東西,注意這裡面返回資料順序要和你Vo類中構造方法引數順序一致,否則會出錯。
以上步驟返回的是兩個表的全部資訊。

第二種:只返回幾個表中想要查詢的部分資料

表結構:
1. 玩家表:player

Field                     Type                           Comment
id                  int(11) unsigned NOT NULL              編號
nickname            varchar(30) NOT NULL                  使用者暱稱
age                 int(11) unsigned NOT NULL             使用者年齡
role_id             int(11) unsigned NOT NULL             角色編號
cst_create          datetime NOT NULL                     建立時間
cst_modify          datetime NOT NULL                     更新時間
del                 int(6) NOT NULL                       是否可用:0-不可用,1-可用
2. 角色表:role

Field                    Type                            Comment
id                  int(11) unsigned NOT NULL            角色編號
name                varchar(30) NOT NULL                 角色名稱
cst_create          datetime NOT NULL                    建立時間
cst_modify          datetime NOT NULL                    更新時間
del                 int(6) unsigned NOT NULL             是否可用:0-不可用,1-可用


新建Vo類:接收多表關聯返回結集,該類中放你返回的資料,需要什麼放什麼
@Data
public class RolePlayerVo { 這裡我只返回玩家姓名和角色名稱等欄位
    
    private String nickName;

    private Integer age;

    private Integer roleId;

    private String name;

    //必須要有建構函式
    public RolePlayerVo(String nickName, Integer age, Integer roleId, String name) {
        this.nickName = nickName;
        this.age = age;
        this.roleId = roleId;
        this.name = name;
    }


    public RolePlayerVo() {
    }
}
controller類:
 @GetMapping
  public Result rolePlayer(@RequestParam Integer pageNo, @RequestParam Integer pageSize){
        return playerService.rolePlayerList(pageNo,pageSize);
    }
Service實現類:
Service介面中方法:返回你定義的Vo泛型的list就行

@Override
    public Result rolePlayerList(Integer pageNo, Integer pageSize) {
        Pageable pageable = PageRequest.of(pageNo,pageSize);
        List<RolePlayerVo> rolePlayerVos = playerDao.findRolePlayerVo(pageable);
        
        return ResultUtil.success(rolePlayerVos);
    }
dao層
 @Query(value = "select new com.cvc.livingcircle.vo.rolePlayer.RolePlayerVo(p.nickName,p.age,p.roleId,r.name) " +
            "from Player p ,Role r where r.id = p.roleId  ")
    List<RolePlayerVo> findRolePlayerVo(Pageable pageable);

/**
也可以根據自己的需要使用inner join\left join\right join等:
 @Query(value = "select new com.cvc.livingcircle.vo.rolePlayer.RolePlayerVo(p.nickName,p.age,p.roleId,r.name) " +
            "from Player p inner join Role r on r.id = p.roleId order By r.id")
    List<RolePlayerVo> findRolePlayerVo(Pageable pageable);  */

注意:new 絕對不能少,後面最好跟全限定類名(不寫有可能找不到這個類),還有new com.cvc.livingcircle.vo.XXXVo( )...括號裡面寫你要查的東西,注意這裡面返回資料順序要和你Vo類中構造方法引數順序一致,否則會出錯。
以上步驟返回的資料是你想要查詢的資料。

相關文章