Spring JPA 联表查询 : OneToMany

前言

我们在实际项目中,除了会碰到一对一的情况,还有一对多的情况,比如一个用户可以有多辆车,而一辆车只能有一个用户等等,今天我们就来一起学习下 OneToMany(一对多)。

源码

@OneToMany 注解实现一对多关系映射。比如用户跟房子的关系, 一个用户可以有好多房子,而一个房子只能一个用户。
老规矩,实例之前先看看源码:

public @interface OneToMany {

    Class targetEntity() default void.class;

    CascadeType[] cascade() default {};

    FetchType fetch() default LAZY;

    String mappedBy() default "";

    boolean orphanRemoval() default false;
}
复制代码

注解属性详情请见 注解属性详解,其中需要注意的是 @OneToManyfetch 的默认值是 LAZY

单向联表

我这里所说的单向联表就是只有一方添加注解;通俗讲就是我可以通过 user 获取到其 house 的信息,而不同通过 house 获取到其 user 的信息。

实例

user 实体类

因为对方是 many 多端,所以这边需要用 List 集合

@Entity
@Data
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    private String name;

    private int age;

    @OneToMany
    @JoinColumn(name = "user_id")
    private List<House> house;

}
复制代码

house 实体类

@Entity
@Data
public class House {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    private String addr;

}
复制代码

小贴士

实例运行之后,大家肯定会发现一个奇怪的问题:user_id 字段明明写在了 user 实体类中,但是实际却添加在 house 表中,这是为啥呢?
因为在 JPA 规范中,一对多的双向关系是由 多端(many) 来维护。就是说 多端(many) 为关系维护端,负责关系的增删改查;一端(one) 则为关系被维护端。

执行请求/user/findById?id=1,控制台打印如下:

Hibernate: 
    select
        user0_.id as id1_2_0_,
        user0_.age as age2_2_0_,
        user0_.name as name3_2_0_ 
    from
        user user0_ 
    where
        user0_.id=?

Hibernate: 
    select
        house0_.user_id as user_id3_1_0_,
        house0_.id as id1_1_0_,
        house0_.id as id1_1_1_,
        house0_.addr as addr2_1_1_ 
    from
        house house0_ 
    where
        house0_.user_id=?
复制代码

查询结果

User(id=1, name=lili, age=11, house=[House(id=1, addr=江苏南京), House(id=2, addr=江苏无锡), House(id=3, addr=江苏苏州)])

双向联表

我们除了需要通过 user 信息来获取其 house 信息外,有时还需要通过 house 信息来获取其 user 信息。但是需要注意的是 user 对于 house 来说,是一对多;而 house 对于 user 来说,是多对一。这时我们就需要引入另一个联表注解 @ManyToOne,在 house 的实体中添加 user 字段,并添加 @ManyToOne 注解。(这里有一个堆栈溢出的问题需要注意一下,详情请见 JPA 错题集 第二个报错信息)

实例

user 实体类

user 实体中 house 字段

@OneToMany
@JoinColumn(name = "user_id")
@JsonIgnore
public List<House> house;
复制代码

house 实体类

@ManyToOne
@JsonIgnore
private User user;
复制代码

执行请求 /house/findById?id=1,控制台打印如下:

Hibernate: 
    select
        house0_.id as id1_1_0_,
        house0_.addr as addr2_1_0_,
        house0_.user_id as user_id3_1_0_,
        user1_.id as id1_2_1_,
        user1_.age as age2_2_1_,
        user1_.name as name3_2_1_ 
    from
        house house0_ 
    left outer join
        user user1_ 
            on house0_.user_id=user1_.id 
    where
        house0_.id=?
2023-04-27 20:35:29.940 TRACE 24272 --- [nio-7777-exec-6] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [INTEGER] - [1]
复制代码

对象获取

有同学可能已经发现了,当添加了 @JsonIgnore 这个属性之后
执行请求 /user/findById?id=1,控制台打印如下:

Hibernate: 
    select
        user0_.id as id1_2_0_,
        user0_.age as age2_2_0_,
        user0_.name as name3_2_0_ 
    from
        user user0_ 
    where
        user0_.id=?
[nio-7777-exec-1] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [INTEGER] - [1]
复制代码

只取进行用户信息的查询,那我的 house 怎么办呢?别急,我会给你们找回来的!
Usercontrol

@GetMapping("findById")
public Optional<User> findById(int id){
    Optional<User> users = userService.findById(id);
    users.get().getHouse().forEach(v->{
        System.out.println(v.getId() + "-"+ v.getAddr());
    });
    return userService.findById(id);
}
复制代码

执行请求 /user/findById?id=1,控制台打印如下:

Hibernate: 
    select
        house0_.user_id as user_id3_1_0_,
        house0_.id as id1_1_0_,
        house0_.id as id1_1_1_,
        house0_.addr as addr2_1_1_,
        house0_.user_id as user_id3_1_1_ 
    from
        house house0_ 
    where
        house0_.user_id=?
[nio-7777-exec-1] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [INTEGER] - [1]
1-南京
2-苏州
3-无锡
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot中使用JPA进行多表查询可以通过使用JPQL查询语句或者使用Spring Data JPA的关联查询来实现。 方法一:使用JPQL查询语句 1. 在实体类中定义好表之间的关联关系,例如使用@ManyToOne、@OneToMany等注解。 2. 在Repository接口中定义自定义的查询方法,使用@Query注解指定JPQL查询语句。 3. 在Service层调用Repository中的查询方法进行查询操作。 示例代码: ```java @Entity @Table(name = "user") public class User { @Id private Long id; // 其他属性和关联关系省略... } @Entity @Table(name = "order") public class Order { @Id private Long id; @ManyToOne @JoinColumn(name = "user_id") private User user; // 其他属性和关联关系省略... } public interface OrderRepository extends JpaRepository<Order, Long> { @Query("SELECT o FROM Order o JOIN FETCH o.user WHERE o.id = :orderId") Order findOrderWithUserById(Long orderId); } ``` 方法二:使用Spring Data JPA的关联查询 1. 在实体类中定义好表之间的关联关系,例如使用@ManyToOne、@OneToMany等注解。 2. 在Repository接口中使用Spring Data JPA提供的关联查询方法进行查询操作。 示例代码: ```java @Entity @Table(name = "user") public class User { @Id private Long id; // 其他属性和关联关系省略... } @Entity @Table(name = "order") public class Order { @Id private Long id; @ManyToOne @JoinColumn(name = "user_id") private User user; // 其他属性和关联关系省略... } public interface OrderRepository extends JpaRepository<Order, Long> { Order findOrderById(Long orderId); } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值