目录

一、多表设计

1.1、表之间关系的划分

1.2、在JPA框架中表关系的分析步骤

二、JPA中的一对多

 2.1、需求背景

2.1、表关系建立

2.3、实体类关系建立以及映射配置

2.4、映射的注解说明

2.5、一对多的操作

2.5.1添加

2.5.2、删除

2.5.3、级联操作

三、JPA中的多对多

3.1、需求背景

3.2、表关系建立

3.3、实体类关系建立以及映射配置

3.4、映射的注解说明

3.5、对多的操作

3.5.1、保存

3.5.2、删除

四、JPA中的一对一

五、Spring Data JPA中的多表查询

5.1、对象导航查询


一、多表设计

1.1、表之间关系的划分

数据库中多表之间存在着三种关系,如图所示。

spring data r2dbc 一对多_一对多

从图可以看出,系统设计的三种实体关系分别为:多对多、一对多和一对一关系。注意:一对多关系可以看为两种:  即一对多,多对一。所以说四种更精确。

 

1.2、在JPA框架中表关系的分析步骤

         在实际开发中,我们数据库的表难免会有相互的关联关系,在操作表的时候就有可能会涉及到多张表的操作。而在这种实现了ORM思想的框架中(如JPA),可以让我们通过操作实体类就实现对数据库表的操作。所以今天我们的学习重点是:掌握配置实体之间的关联关系。

第一步:首先确定两张表之间的关系。

如果关系确定错了,后面做的所有操作就都不可能正确。

第二步:在数据库中实现两张表的关系

第三步:在实体类中描述出两个实体的关系

第四步:配置出实体类和数据库表的关系映射

 

二、JPA中的一对多

 2.1、需求背景

 采用的示例为会议和参会人员。

 会议:就是某个会议。

 参会人员: 就是参加某会议的人员。

 因为只有会议可以选择参会人员,所以从实际的角度会议和参会人员的关系即为一对多。

2.1、表关系建立

在一对多关系中,我们习惯把一的一方称之为主表,把多的一方称之为从表。在数据库中建立一对多的关系,需要使用数据库的外键约束。

什么是外键?

指的是从表中有一列,取值参照主表的主键,这一列就是外键。

2.3、实体类关系建立以及映射配置

在实体类中,由于会议是少的一方,它应该包含多个参会人员,所以实体类要体现出会议中有多个参会人员的信息,代码如下:

/**
 * 会议的实体类
 * 明确使用的注解都是JPA规范的
 * 所以导包都要导入javax.persistence包下的
 */
@Entity
@Table(name = "gs_meeting")
public class GsMeeting {
    @Id
    @GeneratedValue(generator = "system-uuid")
    @GenericGenerator(name = "system-uuid", strategy = "uuid")
    @ApiModelProperty(value = "主键", name = "id", hidden = true)
    private String id;

    @ApiModelProperty(value = "会议名称", name = "meetingName", required = true)
    private String meetingName;

    @ApiModelProperty(value = "会议日期", name = "visitDate", required = true)
    private String visitDate;

    @ApiModelProperty(value = "会议开始时间", name = "startTime", required = true)
    private String startTime;

    @ApiModelProperty(value = "会议结束时间", name = "endTime", required = true)
    private String endTime;

    @ApiModelProperty(value = "会场id", name = "venueId", required = true)
    private String venueId;

    @ApiModelProperty(value = "会场名称", name = "venueName", required = true)
    private String venueName;

    @ApiModelProperty(value = "具体地点", name = "address", required = true)
    private String address;

    @ApiModelProperty(value = "会议流程图", name = "flowImage", required = true)
    private String flowImage;

    @ApiModelProperty(value = "创建时间", name = "createTime", hidden = true)
    private String createTime;

    @ApiModelProperty(value = "修改时间", name = "updateTime", hidden = true)
    private String updateTime;

    @ApiModelProperty(value = "是否删除(0未删除,1删除)", name = "isDelete", hidden = true)
    private Integer isDelete;

    //配置会议和参会人员的一对多关系
    @OneToMany(targetEntity=GsMeetingUser.class, fetch = FetchType.LAZY)
    @JoinColumn(name="meeting_id",referencedColumnName="id")
    private Set<GsMeetingUser> meetingUsers = new HashSet<GsMeetingUser>(0);

}

由于参会人员是多的一方,在实体类中要体现出,(注意在业务逻辑上一个人员也可以对应多个会议,但是实现上没有人员选多个会议的操作,所以定义为一对多,严格上讲应该是多对多),代码如下:

 

**
 * 参会人员的实体类
 *      配置映射关系
 *
 *
 *   1.实体类和表的映射关系
 *      @Entity:声明实体类
 *      @Table : 配置实体类和表的映射关系
 *          name : 配置数据库表的名称
 *   2.实体类中属性和表中字段的映射关系
 *
 *
 */

@Entity
@Table(name = "gs_meeting_user")
public class GsMeetingUser {

    /**
     * @Id:声明主键的配置
     * @GeneratedValue:配置主键的生成策略
     *      strategy
     *          GenerationType.IDENTITY :自增,mysql
     *                 * 底层数据库必须支持自动增长(底层数据库支持的自动增长方式,对id自增)
     *          GenerationType.SEQUENCE : 序列,oracle
     *                  * 底层数据库必须支持序列
     *          GenerationType.TABLE : jpa提供的一种机制,通过一张数据库表的形式帮助我们完成主键自增
     *          GenerationType.AUTO : 由程序自动的帮助我们选择主键生成策略
     * @Column:配置属性和字段的映射关系
     *      name:数据库表中字段的名称
     */
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id; // 参会人员的主键

    @Column(name = "meeting_id") // 指定和表中meeting_id字段的映射关系
    private String meetingId; // 会议id

    @Column(name = "user_id") // 指定和表中user_id字段的映射关系
    private String userId; // 参会人员id

    @Column(name = "is_attend") // 指定和表中is_attend字段的映射关系
    private Integer isAttend; // 是否参会

    @Column(name="seat_number") // 指定和表中seat_number字段的映射关系
    private String seatNumber; // 座位号

    @Column(name="create_time") // 指定和表中create_time字段的映射关系
    private String createTime; // 创建时间

    @Column(name="update_time") // 指定和表中update_time字段的映射关系
    private String updateTime; // 更新时间

    @Column(name="is_delete")  // 指定和表中is_delete字段的映射关系
    private Integer isDelete; // 是否删除

}

 

2.4、映射的注解说明

@OneToMany:

    作用:建立一对多的关系映射

    属性:

     targetEntityClass:指定多的多方的类的字节码

     mappedBy:指定从表实体类中引用主表对象的名称。

     cascade:指定要使用的级联操作

     fetch:指定是否采用延迟加载

     orphanRemoval:是否使用孤儿删除

 

@ManyToOne

    作用:建立多对一的关系

    属性:

     targetEntityClass:指定一的一方实体类字节码

     cascade:指定要使用的级联操作

     fetch:指定是否采用延迟加载

     optional:关联是否可选。如果设置为false,则必须始终存在非空关系。

 

@JoinColumn

     作用:用于定义主键字段和外键字段的对应关系。

     属性:

     name:指定外键字段的名称(从表多)

     referencedColumnName:指定引用主表的主键字段名称(主表1)

     unique:是否唯一。默认值不唯一

     nullable:是否允许为空。默认值允许。

     insertable:是否允许插入。默认值允许。

     updatable:是否允许更新。默认值允许。

     columnDefinition:列的定义信息。

 

2.5、一对多的操作

 

2.5.1添加

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:applicationContext.xml")
public class OneToManyTest {

	@Autowired
	private GsMeetingDao gsMeetingDao ;
	
	/**
	 * 保存操作
	 * 需求:
	 * 	保存一个会议和一个参会人员
	 */
	@Test
	@Transactional  //开启事务
	@Rollback(false)//设置为不回滚
	public void testAdd() {
	    GsMeeting gsMeeting = new GsMeeting();
        gsMeeting.setMeetingName("陕煤杯");
        gsMeeting.setVenueName("神南");
        gsMeeting.setAddress("神木新村");

        GsMeetingUser user = new GsMeetingUser();
        user.setSeatNumber("002");

        gsMeeting.getMeetingUsers().add(user);
        user.setGsMeeting(gsMeeting);
		GsMeetingDao.save(gsMeeting);
	}
}

如果两个实体都保存,我们可以发现在设置了双向关系之后,会发送两条insert语句,一条多余的update语句,那我们的解决是思路很简单,就是一的一方放弃维护权

/**
	 *放弃外键维护权的配置将如下配置改为
	 */
    //设置为
	@OneToMany(mappedBy="gsMeeting")

 

2.5.2、删除

@Autowired
	private GsMeetingDao gsMeetingDao ;
	
	@Test
	@Transactional
	@Rollback(false)//设置为不回滚
	public void testDelete() {
		gsMeetingDao.delete(gsMeeting);
	}

删除操作的说明如下:

删除从表数据:可以随时任意删除。

删除主表数据:

  • 有从表数据

  1、在默认情况下,它会把外键字段置为null,然后删除主表数据。如果在数据库的表                结构上,外键字段有非空约束,默认情况就会报错了。

  2、如果配置了放弃维护关联关系的权利,则不能删除(与外键字段是否允许为null, 没有关系)因为在删除时,它根本不会去更新从表的外键字段了。

  3、如果还想删除,使用级联删除引用

  • 没有从表数据引用:随便删

  在实际开发中,级联删除请慎用!(在一对多的情况下)

 

2.5.3、级联操作

级联操作:指操作一个对象同时操作它的关联对象

使用方法:只需要在操作主体的注解上配置cascade

/**
	 * cascade:配置级联操作
	 * 		CascadeType.MERGE	级联更新
	 * 		CascadeType.PERSIST	级联保存:
	 * 		CascadeType.REFRESH 级联刷新:
	 * 		CascadeType.REMOVE	级联删除:
	 * 		CascadeType.ALL		包含所有
	 */
	@OneToMany(mappedBy="gsMeeting",cascade=CascadeType.ALL)

 

三、JPA中的多对多

 

3.1、需求背景

 采用的示例为用户和角色。

 用户:指的是咱们班的每一个同学。

 角色:指的是咱们班同学的身份信息。

 比如A同学,它是我的学生,其中有个身份就是学生,还是家里的孩子,那么他还有个身份是子女。

 同时B同学,它也具有学生和子女的身份。

 那么任何一个同学都可能具有多个身份。同时学生这个身份可以被多个同学所具有。

 所以我们说,用户和角色之间的关系是多对多。

3.2、表关系建立

多对多的表关系建立靠的是中间表,其中用户表和中间表的关系是一对多,角色表和中间表的关系也是一对多,如下图所示:

spring data r2dbc 一对多_实体类_02

3.3、实体类关系建立以及映射配置

一个用户可以具有多个角色,所以在用户实体类中应该包含多个角色的信息,代码如下

 

/**
 * 用户的数据模型
 */
@Entity
@Table(name="sys_user")
public class SysUser implements Serializable {
	
	@Id
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	@Column(name="user_id")
	private Long userId;
	@Column(name="user_code")
	private String userCode;
	@Column(name="user_name")
	private String userName;
	@Column(name="user_password")
	private String userPassword;
	@Column(name="user_state")
	private String userState;
	
	//多对多关系映射
	@ManyToMany(mappedBy="users")
	private Set<SysRole> roles = new HashSet<SysRole>(0);
	
	public Long getUserId() {
		return userId;
	}
	public void setUserId(Long userId) {
		this.userId = userId;
	}
	public String getUserCode() {
		return userCode;
	}
	public void setUserCode(String userCode) {
		this.userCode = userCode;
	}
	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}
	public String getUserPassword() {
		return userPassword;
	}
	public void setUserPassword(String userPassword) {
		this.userPassword = userPassword;
	}
	public String getUserState() {
		return userState;
	}
	public void setUserState(String userState) {
		this.userState = userState;
	}
	public Set<SysRole> getRoles() {
		return roles;
	}
	public void setRoles(Set<SysRole> roles) {
		this.roles = roles;
	}
	@Override
	public String toString() {
		return "SysUser [userId=" + userId + ", userCode=" + userCode + ", userName=" + userName + ", userPassword="
				+ userPassword + ", userState=" + userState + "]";
	}
}

一个角色可以赋予多个用户,所以在角色实体类中应该包含多个用户的信息,代码如下:

/**
 * 角色的数据模型
 */
@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_memo")
	private String roleMemo;
	
	//多对多关系映射
	@ManyToMany
	@JoinTable(name="user_role_rel",//中间表的名称
			  //中间表user_role_rel字段关联sys_role表的主键字段role_id
			  joinColumns={@JoinColumn(name="role_id",referencedColumnName="role_id")},
			  //中间表user_role_rel的字段关联sys_user表的主键user_id
			  inverseJoinColumns={@JoinColumn(name="user_id",referencedColumnName="user_id")}
	)
	private Set<SysUser> users = new HashSet<SysUser>(0);
	
	
	public Long getRoleId() {
		return roleId;
	}
	public void setRoleId(Long roleId) {
		this.roleId = roleId;
	}
	public String getRoleName() {
		return roleName;
	}
	public void setRoleName(String roleName) {
		this.roleName = roleName;
	}
	public String getRoleMemo() {
		return roleMemo;
	}
	public void setRoleMemo(String roleMemo) {
		this.roleMemo = roleMemo;
	}
	public Set<SysUser> getUsers() {
		return users;
	}
	public void setUsers(Set<SysUser> users) {
		this.users = users;
	}
	@Override
	public String toString() {
		return "SysRole [roleId=" + roleId + ", roleName=" + roleName + ", roleMemo=" + roleMemo + "]";
	}
}

 

3.4、映射的注解说明

@ManyToMany

作用:用于映射多对多关系

属性:

cascade:配置级联操作。

fetch:配置是否采用延迟加载。

     targetEntity:配置目标的实体类。映射多对多的时候不用写。

 

@JoinTable

    作用:针对中间表的配置

    属性:

     nam:配置中间表的名称

     joinColumns:中间表的外键字段关联当前实体类所对应表的主键字段   

     inverseJoinColumn:中间表的外键字段关联对方表的主键字段

    

@JoinColumn

    作用:用于定义主键字段和外键字段的对应关系。

    属性:

     name:指定外键字段的名称

     referencedColumnName:指定引用主表的主键字段名称

     unique:是否唯一。默认值不唯一

     nullable:是否允许为空。默认值允许。

     insertable:是否允许插入。默认值允许。

     updatable:是否允许更新。默认值允许。

     columnDefinition:列的定义信息。

 

3.5、对多的操作

3.5.1、保存

@Autowired
	private UserDao userDao;
	
	@Autowired
	private RoleDao roleDao;
	/**
	 * 需求:
	 * 	保存用户和角色
	 * 要求:
	 * 	创建2个用户和3个角色
	 * 	让1号用户具有1号和2号角色(双向的)
	 * 	让2号用户具有2号和3号角色(双向的)
	 *  保存用户和角色
	 * 问题:
	 *  在保存时,会出现主键重复的错误,因为都是要往中间表中保存数据造成的。
	 * 解决办法:
	 * 	让任意一方放弃维护关联关系的权利
	 */
	@Test
	@Transactional  //开启事务
	@Rollback(false)//设置为不回滚
	public void test1(){
		//创建对象
		SysUser u1 = new SysUser();
		u1.setUserName("用户1");
		SysRole r1 = new SysRole();
		r1.setRoleName("角色1");
		//建立关联关系
		u1.getRoles().add(r1);
		r1.getUsers().add(u1);
		//保存
		roleDao.save(r1);
		userDao.save(u1);
	}

在多对多(保存)中,如果双向都设置关系,意味着双方都维护中间表,都会往中间表插入数据,中间表的2个字段又作为联合主键,所以报错,主键重复,解决保存失败的问题:只需要在任意一方放弃对中间表的维护权即可,推荐在被动的一方放弃,配置如下:

/放弃对中间表的维护权,解决保存中主键冲突的问题

@ManyToMany(mappedBy="roles")

private Set<SysUser> users = new HashSet<SysUser>(0);

 

3.5.2、删除

 

@Autowired
	private UserDao userDao;
	/**
	 * 删除操作
	 * 	在多对多的删除时,双向级联删除根本不能配置
	 * 禁用
	 *	如果配了的话,如果数据之间有相互引用关系,可能会清空所有数据
	 */
	@Test
	@Transactional
	@Rollback(false)//设置为不回滚
	public void testDelete() {
		userDao.delete(1l);
	}

 

四、JPA中的一对一

         一对一关系相对而言用的比较少,如人员与部门,字典键与字典值,表单与审批记录......

        在本次开发的项目中遇到表单与审批记录的关系(每创建一个表单对应一条审批记录)

        项目表单:

@Data
@Entity
@Table(name = "project")
@ApiModel(value = "项目表对象")
@SQLDelete(sql = "update project set is_delete = 1 where id = ?")
@Where(clause = "is_delete = 0")
@DynamicInsert
@Accessors(chain = true)
public class Project {
    @Id
    @GeneratedValue(generator = "system-uuid")
    @GenericGenerator(name = "system-uuid", strategy = "uuid")
    @ApiModelProperty(value = "ID")
    private String id;

    @Column(name = "apply_id"   )
    @ApiModelProperty(value="审批申请表id", name="applyId")
    private String applyId;

    @Column(name = "project_level")
    @ApiModelProperty(value="项目级别 0 部门/中心级项目,1 公司级项目", name="projectLevel")
    private Integer projectLevel;

    @Column(name = "project_name")
    @ApiModelProperty(value="项目名称", name="projectName")
    private String projectName;

    @Column(name = "project_type_id")
    @ApiModelProperty(value="项目类型id", name="projectTypeId")
    private String projectTypeId;

    @Column(name = "project_type_name")
    @ApiModelProperty(value="项目类型名称", name="projectTypeName")
    private String projectTypeName;

    @Column(name = "project_start_time")
    @ApiModelProperty(value="项目开始时间", name="projectStartTime")
    private String projectStartTime;

    @Column(name = "project_end_time")
    @ApiModelProperty(value="项目结束时间", name="projectEndTime")
    private String projectEndTime;

    @Column(name = "project_complate_time")
    @ApiModelProperty(value="实际完成时间", name="projectComplateTime")
    private String projectComplateTime;

    @Column(name = "project_desc")
    @ApiModelProperty(value="项目描述", name="projectDesc")
    private String projectDesc;

    @Column(name = "project_status")
    @ApiModelProperty(value="项目状态 0:未开始,1:处理中 2:验收中,3:已完成,4:超期未完成,5:超期已完成", name="projectStatus")
    private Integer projectStatus;

    @Column(name = "project_overdue_num")
    @ApiModelProperty(value="超期次数 默认0,无超期", name="projectOverdueNum")
    private Integer projectOverdueNum;

    @Column(name = "project_delay_num")
    @ApiModelProperty(value="延迟次数 默认0,无延迟", name="projectDelayNum")
    private Integer projectDelayNum;

    @Column(name = "project_public_status")
    @ApiModelProperty(value="发布状态 0:草稿,1:发布", name="projectPublicStatus")
    private Integer projectPublicStatus;

    @Column(name = "project_schedule")
    @ApiModelProperty(value="项目亮灯进度,0:白灯 1:黑灯,2:红灯", name="projectSchedule")
    private Integer projectSchedule;

    @Column(name = "project_nature_id")
    @ApiModelProperty(value="项目性质id", name="projectNatureId")
    private String projectNatureId;

    @Column(name = "project_nature_name")
    @ApiModelProperty(value="项目性质名称", name="projectNatureName")
    private String projectNatureName;

    @Column(name = "project_liable_id")
    @ApiModelProperty(value="项目负责人id", name="projectLiableId")
    private String projectLiableId;

    @Column(name = "project_liable_name")
    @ApiModelProperty(value="项目负责人名称", name="projectLiableName")
    private String projectLiableName;

    @Column(name = "project_department_id")
    @ApiModelProperty(value="项目部门ID(项目创建人当前部门id)", name="projectDepartmentId")
    private String projectDepartmentId;

    @Column(name = "project_department_name")
    @ApiModelProperty(value="项目部门名称(项目创建人当前部门名称)", name="projectDepartmentName")
    private String projectDepartmentName;

    @Column(name = "project_examine_dept_id")
    @ApiModelProperty(value="审核部门id", name="projectExamineDeptId")
    private String projectExamineDeptId;

    @Column(name = "project_examine_dept_name")
    @ApiModelProperty(value="审核部门名称", name="projectExamineDeptName")
    private String projectExamineDeptName;

    @Column(name = "cooperation_dept_id")
    @ApiModelProperty(value="协作部门id", name="cooperationDeptId")
    private String cooperationDeptId;

    @Column(name = "cooperation_dept_name")
    @ApiModelProperty(value="协作部门名称", name="cooperationDeptName")
    private String cooperationDeptName;

    @Column(name = "create_user_id")
    @ApiModelProperty(value="创建人ID", name="createUserId")
    private String createUserId;

    @Column(name = "create_user_name")
    @ApiModelProperty(value="创建人名称", name="createUserName")
    private String createUserName;

    @Column(name = "create_time")
    @ApiModelProperty(value="创建时间", name="createTime")
    private String createTime;

    @Column(name = "is_delete")
    @ApiModelProperty(value="删除标记", name="isDelete")
    private Integer isDelete;

    @OneToOne(fetch = FetchType.LAZY)
    @NotFound(action= NotFoundAction.IGNORE) // 由于springBootjpa2.0中findById()中查找不到就会报异常,导致本次查询异常,此标签就是为了解决这个问题
    @JoinColumn(name="apply_id",referencedColumnName = "id",foreignKey = @ForeignKey(value = ConstraintMode.NO_CONSTRAINT), insertable=false, updatable=false)
    @ApiModelProperty(value = "审批申请", hidden = true)
    private ProjectApply projectApply;

}

  审批记录:

@Data
@Entity
@Table(name = "project_apply")
@ApiModel(value = "审批申请表对象")
@SQLDelete(sql = "update project_apply set is_delete = 1 where id = ?")
@Where(clause = "is_delete = 0")
@DynamicInsert
@Accessors(chain = true)
public class ProjectApply {
    @Id
    @GeneratedValue(generator = "system-uuid")
    @GenericGenerator(name = "system-uuid", strategy = "uuid")
    @Column(name = "id")
    @ApiModelProperty(value = "ID")
    private String id;

    @Column(name = "instance_id",nullable = false)
    @ApiModelProperty(value="流程ID", name="instanceId")
    private String instanceId;

    @Column(name = "form_id",nullable = false)
    @ApiModelProperty(value="表单ID", name="formId")
    private String formId;

    @Column(name = "rask_mark",nullable = false)
    @ApiModelProperty(value="任务标识(工作流任务内部表示)", name="raskMark")
    private String raskMark;

    @Column(name = "flow_class",nullable = false)
    @ApiModelProperty(value="分类(项目创建/项目延期/项目变更/项目取消/项目验收/子项目验收)", name="flowClass")
    private String flowClass;

    @Column(name = "title",nullable = false)
    @ApiModelProperty(value="流程标题", name="title")
    private String title;

    @Column(name = "org_id",nullable = false)
    @ApiModelProperty(value="审批申请部门ID", name="orgId")
    private String orgId;

    @Column(name = "org_type",nullable = false)
    @ApiModelProperty(value="审批申请部门类型", name="orgType")
    private String orgType;

    @Column(name = "org_name",nullable = false)
    @ApiModelProperty(value="审批申请部门名称", name="orgName")
    private String orgName;

    @Column(name = "apply_date",nullable = false)
    @ApiModelProperty(value="审批申请时间", name="applyDate")
    private String applyDate;

    @Column(name = "apply_username",nullable = false)
    @ApiModelProperty(value="审批申请人名称", name="applyUsername")
    private String applyUsername;

    @Column(name = "apply_state",nullable = false)
    @ApiModelProperty(value="审核状态 0:未提交,1:审核中,2:审核通过,3:审核不通过", name="applyState")
    private Integer applyState;

    @Column(name = "apply_result",nullable = false)
    @ApiModelProperty(value="申请结果(通过、驳回)", name="applyResult")
    private String applyResult;

    @Column(name = "remarks",nullable = false)
    @ApiModelProperty(value="备注", name="remarks")
    private String remarks;

    @Column(name = "create_user_id",nullable = false)
    @ApiModelProperty(value="创建人ID", name="createUserId")
    private String createUserId;

    @Column(name = "create_user_name",nullable = false)
    @ApiModelProperty(value="创建人名称", name="createUserName")
    private String createUserName;

    @Column(name = "create_time",nullable = false)
    @ApiModelProperty(value="创建时间", name="createTime")
    private String createTime;

    @Column(name = "is_delete",nullable = false)
    @ApiModelProperty(value="删除标记", name="isDelete")
    private Integer isDelete;

}

 

 

 

 

五、Spring Data JPA中的多表查询

 

5.1、对象导航查询

        对象图导航检索方式是根据已经加载的对象,导航到他的关联对象。它利用类与类之间的关系来检索对象。例如:我们通过ID查询方式查出一个客户,可以调用GsMeeting类中的getMeetingUsers()

方法来获取该会议的所有参会人员。对象导航查询的使用要求是:两个对象之间必须存在关联关系。

查询一个客户,获取该客户下的所有联系人

 

@Autowired
	private GsMeetingDao gsMeetingDao ;
	
	@Test
	//由于是在java代码中测试,为了解决no session问题,将操作配置到同一个事务中
	@Transactional 
	public void testFind() {
		GsMeetingDao meeting= gsMeetingDao.findOne(5l);
		Set<GsMeetingUser> meetingUsers  = customer.getMeetingUsers() ;//对象导航查询
		for(GsMeetingUser meetingUser: meetingUsers) {
  			System.out.println(meetingUser);
		}
	}

对象导航查询的问题分析

问题:我们查询会议时,要不要把参会人员查询出来?

分析:如果我们不查的话,在用的时候还要自己写代码,调用方法去查询。如果我们查出来的,不使用时又会白白的浪费了服务器内存。

解决:采用延迟加载的思想。通过配置的方式来设定当我们在需要使用时,发起真正的查询

/**
	 * 在会议对象的@OneToMany注解中添加fetch属性
	 * 		FetchType.EAGER	:立即加载
	 * 		FetchType.LAZY	:延迟加载
	 */
	@OneToMany(mappedBy="customer",fetch=FetchType.EAGER)
	private Set<GsMeetingUser> meetingUsers = new HashSet<GsMeetingUser>(0)