由于之前较多接触的是mybatis,当刚开始做springbootjpa项目是还是有些许困惑的;
@MapsId
官方的解释是
Designates a <code>ManyToOne</code> or <code>OneToOne</code> relationship attribute that provides the mapping for an {@link EmbeddedId} primary key, an attribute within an <code>EmbeddedId</code> primary key, or a simple primary key of the parent entity. The <code>value</code> element specifies the attribute within a composite key to which the relationship attribute corresponds. If the entity's primary key is of the same Java type as the primary key of the entity referenced by the relationship, the value attribute is not specified.
大概意思是:映射EmbeddedId主键中的一个属性,或者是父实体的普通主键,value元素指定复合主键的属性对应关系,如果实体的主键与关系引用的实体的主键具有相同的Java类型,则不指定value属性。(意思很难懂)
经过摸索,得到一些demo,如下
//包换复合主键的实体
@Entity
public class ClassStudent implements Serializable {
@EmbeddedId
private ClassStudentId id;//复合主键
private String msg;
@MapsId("studentId")
@OneToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "student_id")
private Student student;
...geter and setter
}
//可嵌入的类 在本例子中表示复合主键
@Embeddable//表示可内嵌
public class ClassStudentId implements Serializable {
private Integer studentId;
private Integer classId;
//geter and setter
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ClassStudentId that = (ClassStudentId) o;
return Objects.equals(studentId, that.studentId) &&
Objects.equals(classId, that.classId);
}
@Override
public int hashCode() {
return Objects.hash(studentId, classId);
}
}
//主题一对一对应的类
@Entity
public class Student implements Serializable {
@Id
@Column(name = "student_id",
columnDefinition = "INT(11) UNSIGNED NOT NULL COMMENT '学生id'"
)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "student_name",
columnDefinition = "VARCHAR(255) COMMENT '学生姓名'"
)
private String name;
@Column(name = "student_age",
columnDefinition = "INT(11) UNSIGNED COMMENT '学生年龄'"
)
private Integer age;
...getter and setter
}
之前已经写出来了,查询没有问题,但是在保存的时候总是报错,大概是 assign id from null from property [student],表示需要相应的对应student,这是本人以为数据库中是不存在该字段的,所以就没有去管student,但是它们确实存在对应关系,保存时应该把student查询出来进行保存.具体代码如下:
@PostMapping
public Object add(@RequestParam Integer studentId,@RequestParam Integer classId ){
ClassStudent classStudent = new ClassStudent();
Optional<Student> byId = studentRepository.findById(studentId);//报错时缺少的代码
if(byId.isPresent()){
ClassStudentId id = new ClassStudentId();
id.setStudentId(studentId);//报错时缺少的代码
id.setClassId(classId);
classStudent.setId(id);
classStudent.setMsg("走读");
classStudent.setStudent(byId.get());
}
@EmbeddedId和@IdClass
@EmbeddedId的用法上面已经展示,与之对应的有@IdClass,当使用idclass时,实体中须有和idclass类中属性个数的主键,并且一致.下边展示代码:
//作为主键id
@Data
public class StreamerSpecialityId implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 播主ID
**/
private Integer streamerId;
/**
* 播主服务ID
*/
private Long specialityId;
}
//实体类
@Entity
@Table(name = "pls_service")
@IdClass(value = StreamerSpecialityId.class)
@Data
@EqualsAndHashCode(callSuper = true)
public class StreamerSpecialityEntity extends BaseEntity {
private static final long serialVersionUID = 1L;
/**
* 播主ID
*/
@Id
@Column(
name = "streamer_id",
columnDefinition = "INT(11) UNSIGNED NOT NULL COMMENT '播主ID'"
)
private Integer streamerId = 0;
/**
* 专长ID
*/
@Id
@Column(
name = "speciality_id",
columnDefinition = "INT(11) UNSIGNED NOT NULL COMMENT '专长ID'"
)
private Long specialityId = 0L;
/**
* 专长
*/
@MapsId("specialityId")//对应复合主键的其中一个
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "speciality_id")
private SpecialityEntity speciality;
}
@Entity
@Table(name = "pls_speciality")
@Data
@EqualsAndHashCode(callSuper = true)
public class SpecialityEntity extends BaseEntity {
private static final long serialVersionUID = 1L;
/**
* ID
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
/**
* 播主ID
*/
@Column(
name = "streamer_id",
columnDefinition = "INT(11) UNSIGNED NOT NULL COMMENT '播主ID'"
)
private Integer streamerId = 0;
/**
* 服务名称
*/
@Column(
name = "name",
columnDefinition = "VARCHAR(32) NOT NULL COMMENT '服务名称'"
)
private String name = "";
/**
* 是否内置
*/
@Column(
name = "is_buildin",
columnDefinition = "TINYINT(1) NOT NULL COMMENT '是否内置'"
)
private Boolean buildin = Boolean.FALSE;
}
保存和修改时需要报关联的实体设置上(对应关系是内联的),不然就走不通