当前位置:   article > 正文

JPA的一对一、一对多、多对多查询_jpa一对多查询

jpa一对多查询

JPA的一对一、一对多、多对多查询

上一节直通车

SpringBoot整合SpringData JPA

级联类型

参考文章:
JPA概念解析:CascadeType(各种级联操作)详解

Lombok注解引发的问题

@Data在JPA中要慎用,因为重写的toString、equals、hashCode都会将关联的实体类对象包含进去,导致执行查询时循环调用到栈溢出
建议:

  1. 面对一对多的情况(即类中包含其他类的集合结果集的),不使用 @Data@EqualsAndHashCode@ToString ,重写toString、equals和hashCode
  2. 遇到equals和hashCode的问题时,依然使用@EqualsAndHashCode,但要通过属性exclude去掉集合类型的属性,例如:@EqualsAndHashCode(exclude = {"blogs","roles"})

User——用户实体(对应多个Blog、多个Role)

/**
 * @Description 用户表
 * @author Evad.Wu
 * @date 2022-06-16
 */
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(exclude = {"blogs","roles"})
@Accessors(chain = true)
@Entity
@Table(name = "user")
public class User implements Serializable {
	private static final long serialVersionUID = 1L;

	@Id
	@GenericGenerator(name = "idGenerator", strategy = "uuid")
	@GeneratedValue(generator = "idGenerator")
	@Column(name = "id")
	private Long id;
	@Column(name = "username")
	private String username;
	@Column(name = "avatar")
	private String avatar;
	@Column(name = "email")
	private String email;
	@Column(name = "password")
	private String password;
	@Column(name = "status")
	private Integer status;
	@Column(name = "created")
	private Date created;
	@Column(name = "last_login")
	private Date lastLogin;
	@Column(name = "admin")
	private boolean admin;
	@Column(name = "telephone")
	private String telephone;
	@Column(name = "identification")
	private String identification;
	@Column(name = "introduction")
	private String introduction;

	@OneToMany(mappedBy = "user", cascade = CascadeType.ALL,fetch = FetchType.LAZY)
	private Set<Blog> blogs;

	@ManyToMany(targetEntity = Role.class, cascade = {CascadeType.PERSIST, CascadeType.MERGE}, fetch = FetchType.LAZY)
	@JoinTable(name = "tb_user_role",
			joinColumns = {@JoinColumn(name = "user_id", referencedColumnName = "id")},
			inverseJoinColumns = {@JoinColumn(name = "role_id", referencedColumnName = "id")})
	private Set<Role> roles;

	@Override
	public String toString() {
		return "User{" +
				"id=" + id +
				", username='" + username + '\'' +
				", avatar='" + avatar + '\'' +
				", email='" + email + '\'' +
				", password='" + password + '\'' +
				", status=" + status +
				", created=" + created +
				", lastLogin=" + lastLogin +
				", admin=" + admin +
				", telephone='" + telephone + '\'' +
				", identification='" + identification + '\'' +
				", introduction='" + introduction + '\'' +
				'}';
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71

Blog——博客实体(对应一个User)

/**
 * @Description 博客表
 * @author Evad.Wu
 * @date 2022-06-17
 */
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(exclude = {"reviewSet","user"})
@Accessors(chain = true)
@Entity
@Table(name = "blog")
public class Blog implements Serializable {

	private static final long serialVersionUID = 1L;

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name = "id")
	private Long id;
	@Column(name = "user_id")
	private Long userId;
	@Column(name = "examine_id")
	private String examineId;
	@Column(name = "title")
	private String title;
	@Column(name = "description")
	private String description;
	@Column(name = "content")
	private String content;
	@Column(name = "created")
	private Date created;
	@Column(name = "status")
	private Integer status;
	@Column(name = "index_img")
	private String indexImg;
	@Column(name = "reading")
	private Long reading;

	@ManyToOne(targetEntity = User.class,cascade = CascadeType.ALL,fetch = FetchType.LAZY)
	@JoinColumn(name = "user_id",insertable = false,updatable = false)
	private User user;

	@Override
	public String toString() {
		return "Blog{" +
				"id=" + id +
				", userId=" + userId +
				", examineId='" + examineId + '\'' +
				", title='" + title + '\'' +
				", description='" + description + '\'' +
				", content='" + content + '\'' +
				", created=" + created +
				", status=" + status +
				", indexImg='" + indexImg + '\'' +
				", reading=" + reading +
				'}';
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60

Role——角色实体(对应多个User)

@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
@ToString
@EqualsAndHashCode(callSuper = false)
@Builder

@Entity
@Table(name = "tb_role")
public class Role extends BaseModel implements Serializable {
	private static final long serialVersionUID = 2480455193854374245L;

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private Long id;

	@Column(name = "role_code")
	private String roleCode;

	@Column(name = "role_name")
	private String roleName;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

BaseModel——基本审计属性

@Data
@MappedSuperclass
@DynamicInsert
@EntityListeners(AuditingEntityListener.class)
public class BaseModel implements Serializable {
    private static final long serialVersionUID = -1152053885220920998L;

    /**
     * 创建人
     */
    @CreatedBy
    @Column(name = "creator", updatable = false, length = 64)
    private String creator;
    /**
     * 创建时间
     */
    @CreatedDate
    @Column(name = "create_time", updatable = false)
    private Date createTime;
    /**
     * 修改人
     */
    @LastModifiedBy
    @Column(name = "modifier", length = 64)
    private String modifier;
    /**
     * 修改时间
     */
    @LastModifiedDate
    @Column(name = "modify_time")
    private Date modifyTime;
    /**
     * 数据可见
     */
    @Column(name = "visible",columnDefinition = "TINYINT DEFAULT 1")
    @ColumnDefault("1")
    private Boolean visible;
    /**
     * 版本
     */
    @Version
    @Column(name = "rec_ver")
    private Long recVer;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

一对一、一对多(多对一)

区别只是类型是单个对象还是集合对象

User类

@OneToMany(mappedBy = "user", cascade = CascadeType.ALL,fetch = FetchType.LAZY)
private Set<Blog> blogs;
  • 1
  • 2

Blog类:

@ManyToOne(targetEntity = User.class,cascade = CascadeType.ALL,fetch = FetchType.LAZY)
@JoinColumn(name = "user_id",insertable = false,updatable = false)
private User user;
  • 1
  • 2
  • 3

一对多要相互依赖,首先有多对一,这里Blog类中需要定义一个User,并添加注解@JoinColumn,指定name关联的字段。
然后User类中需要定义Blog集合,接收多个Blog对象
注意:insertableupdatable都置为false,因为Blog类中的userId和User类中的id都指向同一个数据库字段,这样就会导致级联更新时重复修改而报错。

测试代码:一对一

/**
 * 一对多 1: User N: Blog
 */
@Test
public void oneMore() {
	List<Long> userIds = new ArrayList<>();
	userIds.add(2L);
	userIds.add(4L);
	List<User> userList = userRepository.findAllById(userIds);
	for (User user : userList) {
		System.out.println("user: " + user);
		Set<Blog> blogs = user.getBlogs();
		for (Blog blog : blogs) {
			System.out.println("blog: " + blog);
		}
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

在这里插入图片描述

测试代码:多对一

/**
 * 多对一 N: Blog 1: User
 */
@Test
public void moreOne() {
	List<Long> blogIds = new ArrayList<>();
	blogIds.add(9L);
	blogIds.add(10L);
	List<Blog> blogList = blogRepository.findAllById(blogIds);
	for (Blog blog : blogList) {
		System.out.println("blogId: " + blog.getId());
		System.out.println("user: " + blog.getUser());
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

在这里插入图片描述

多对多

Role

/**
 * @Description 角色
 * @author Evad.Wu
 * @date 2022-06-21
 */
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(exclude = {"reviewSet","user"})
@Entity
@Table(name = "tb_role")
public class Role {
	@Id
	@GenericGenerator(name = "idGenerator", strategy = "uuid")
	@GeneratedValue(generator = "idGenerator")
	private String id;

	@Column(name = "user_id")
	private Long userId;

	@Column(name = "role_name")
	private String roleName;

	@Override
	public String toString() {
		return "Role{" +
				"id='" + id + '\'' +
				", userId=" + userId +
				", roleName='" + roleName + '\'' +
				'}';
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

User

@ManyToMany(targetEntity = Role.class, cascade = {CascadeType.PERSIST, CascadeType.MERGE}, fetch = FetchType.LAZY)
@JoinTable(name = "tb_user_role",
		joinColumns = {@JoinColumn(name = "user_id", referencedColumnName = "id")},
		inverseJoinColumns = {@JoinColumn(name = "role_id", referencedColumnName = "id")})
private Set<Role> roles;
  • 1
  • 2
  • 3
  • 4
  • 5
  1. 多对多不需要互相依赖,只要在需要使用的一方添加即可
  2. 多对多是需要中间表来连接两端的,需要添加@JoinTable注解,name为中间表的名字,如果数据库中没有则会创建
  3. joinColumnsinverseJoinColumns@JoinColumnname属性对应中间表中两端的连接字段,referencedColumnName则是每张表中用于连接的字段
    在这里插入图片描述

测试代码:多对多

/**
 * 多对多:N: User N: Role / N: Role N: User
 */
@Test
public void userRoleM2M() {
	Optional<User> userOptional = userRepository.findById(51L);
	User user = userOptional.get();
	System.out.println("userId: " + user.getId());
	Set<Role> roles = user.getRoles();
	for (Role role : roles) {
		System.out.println("role: " + role);
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

在这里插入图片描述

参考网址

JPA概念解析:CascadeType(各种级联操作)详解

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/530956
推荐阅读
相关标签
  

闽ICP备14008679号