JPA关联
1.JPA多表查询
多表查询在Spring DataJPA 中有两种实现方式,第一种是创建一个结果集的接口来接收多表查询后的结果,第二种是利用JPA的关联映射来实现。
多表连接查询
1.在entity包下创建一个SysRole 实体类和SysUser实体类
@Entity
@Table(name = "sys_user")
@Data
public class SysUser implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "user_id")
private long userId;
@Column(name = "user_name")
private String userName;
@Column(name = "user_password")
private String userPassword;
@Column(name = "user_role_id")
private long userRoleId;
@Column(name = "user_flag")
private Integer userFlag;
//省略构造方法
@Entity
@Table(name = "sys_role")
public class SysRole implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "role_id")
private long roleId;
@Column(name = "role_name")
private String roleName;
@Column(name = "role_desc")
private String roleDesc;
@Column(name = "role_flag")
private Integer roleFlag;
//省略构造方法
2.在vo包下创建一个UserInfo接口,里面提供所需数据的getter方法,其中包括用户数据和角色名称(roleName)
public interface UserInfo {
public Long getUserId();
public String getUserName();
public String getUserPassword();
public Long getUserRoleId();
public Integer getUserFlag();
//角色名称
public String getRoleName();
}
3.在UserRepository中添加查询方法,返回值设置为UserInfo
public interface UserRepository extends JpaRepository<SysUser,Long> {
@Query("SELECT u.userId as userId,u.userName as userName,u.userPassword as userPassword," +
"u.userFlag as userFlag,u.userRoleId as userRoleId,r.roleName as roleName FROM " +
"SysUser u,SysRole r WHERE u.userRoleId = r.roleId AND u.userId=?1")
public UserInfo getUserInfo(Long id);
}
注意:此处的HQL,必须向实体类和属性编写;获取到的属性必须指定别名;
4.测试验证
@Test
public void tsteGetUserInfo(){
UserInfo userInfo = userRepository.getUserInfo(19L);
System.out.println("userName:" +userInfo.getUserName());
System.out.println("roleName:" +userInfo.getRoleName());
}
结果:
第二种关联映射:
单向多对一关联
1.修改SysUser实体类,添加关联SysRole对象
@Entity
@Table(name = "sys_user")
@Data
public class SysUser implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "user_id")
private long userId;
@Column(name = "user_name")
private String userName;
@Column(name = "user_password")
private String userPassword;
// @Column(name = "user_role_id")
// private long userRoleId;
@ManyToOne(targetEntity = SysRole.class)
@JoinColumn(name = "user_role_id")
private SysRole sysRole;
@Column(name = "user_flag")
private Integer userFlag;
2.创建UserRepository
public interface UserRepository extends JpaRepository<SysUser,Long> {
}
3.测试
@Test
public void testGet() {
SysUser sysUser = userRepository.findById(19L).get();
System.out.println("userName:" +sysUser.getUserName());
System.out.println("rolenName:" + sysUser.getSysRole().getRoleName());
}
执行结果为:
从输出的SQL语句可以发现,执行查询SysUser,关联查询了SysRole数据,并将SysRole相关联数据自动封装在SysUser对象的Role属性中。
双向一对多关联
1.修改SysRole实体类,添加关联的User对象集合
@Entity
@Table(name = "sys_role")
public class SysRole implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "role_id")
private long roleId;
@Column(name = "role_name")
private String roleName;
@Column(name = "role_desc")
private String roleDesc;
@Column(name = "role_flag")
private Integer roleFlag;
@OneToMany(targetEntity = SysUser.class,fetch = FetchType.LAZY,
cascade = CascadeType.ALL,mappedBy = "sysRole")
private Set<SysUser> userSet = new HashSet<SysUser>();
修改过后的Role实体类中,新增了Set userSet 属性(使用Set 集合可避免重复对象的问题),用来表示一对多关联,在该属上,我们添加了@OneTOMany注解,映射一对多关联关系。
●targetEntity属性表示关联的实体类型
●fetch属性表示加载策略,FetchType 取值有LAZY 及EAGER, LAZY表示延迟加载,EAGER表示立即加载。@ManyToOne 注解也包含该属性,且默认值为EAGER,表示立即加载,所以查询User时通过左外关联立即获取Role数据; @OneToMany 注解该属性默认值为LAZY。
●cascade属性表示级联操作,CascadeType 取值有PERSIST、REMOVE、ALL… 等。PERSIST表示级联持久化(保存)操作,REMOVE 级联删除,ALL 级联所有操作。@ManyToOne注解也包含该属性,但一般不在多的一 方进 行级联操作。
●mappedBy属性用来设置对象之间的关系维护方(关系维护通过操作外键完成)。如不指定mappedBy属性,则对象均由自已维护关系(外键),操作一方对象时, 会额外产生更新外键的SQL语句。所以一般在@OneToMany注解中指定mappedBy属性,且属性值为多方对象中关联的一方属性名, 并且此时一方实体中不能添加@JoinColumn注解。
2、创建RoleRepository
public interface RoleRepository extends JpaRepository<SysRole,Long> {
}
3.测试查询
@Test
public void testGet1(){
SysRole sysRole = roleRepository.findById(8L).get();
System.out.println("roleName:" +sysRole.getRoleName());
// System.out.println("users.size:"+sysRole.Users().size());
}
4.测试级联操作:级联新增
@Test
public void testAdd(){
//测试级联新增
SysRole sysRole = new SysRole();
sysRole.setRoleName("小强");
sysRole.setRoleDesc("演示级联新增角色和用户");
sysRole.setRoleFlag(1);
SysUser sysUser = new SysUser();
sysUser.setUserName("测试用户1");
sysUser.setUserPassword("123456");
sysUser.setSysRole(sysRole);
sysUser.setUserFlag(1);
SysUser sysUser2 = new SysUser();
sysUser2.setUserName("测试用户2");
sysUser2.setUserPassword("123456");
sysUser2.setSysRole(sysRole);
sysUser2.setUserFlag(1);
sysRole.getUserSet().add(sysUser);
sysRole.getUserSet().add(sysUser2);
roleRepository.save(sysRole);
}