从零开始 Spring Boot 52:@Embedded 和 @Embeddable
图源:简书 (jianshu.com)
这篇文章会介绍@Embedded
和@Embeddable
两个注解在 JPA 中的用法。
简单示例
先看一个示例:
@AllArgsConstructor
@Builder
@Data
@Entity
@Table(name = "user_student")
@Accessors(chain = true)
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@EqualsAndHashCode.Include
private Long id;
@Column(length = 25, nullable = false)
private String name;
@Column(length = 50, nullable = false)
private String address;
@Column(length = 25)
private String contactsName;
@Column(length = 50)
private String contactsAddress;
@Column(length = 15)
private String contactsPhone;
public Student() {
}
}
这里使用了 Lombok 相关注解(比如
@Builder
)帮助构建实体类,详细内容可以阅读我的相关文章。
user_student
是一个学生表,其中的contacts_
开头的字段保存联系人信息,这体现在实体类中就是以contacts
开头的属性。
测试用例:
@Test
@SneakyThrows
void testAddNewStudent() {
Student newStudent = Student.builder()
.address("宁安大街101号")
.name("icexmoon")
.contactsName("lalala")
.contactsAddress("北京大街100号")
.contactsPhone("123456789")
.build();
studentRepository.save(newStudent);
Assertions.assertNotNull(newStudent.getId());
ObjectMapper om = new ObjectMapper();
var json = om.writeValueAsString(newStudent);
System.out.println(json);
}
这样做并没有什么问题,但Student
这个实体类并不具备良好的“结构化”,换言之我们很难将其中的联系人部分进行代码重用。
因此,接下来我们要想办法将Student
中的联系人部分信息提取出来单独作为一个类型存在,这可以借助 JPA 的@Embedded
和@Embeddable
注解完成。
@Embedded 和 @Embeddable
先定义一个联系人类:
@Embeddable
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Contacts {
private String name;
private String address;
private String phone;
}
使用@Embedded
和@Embeddable
“改造”Student
类:
@AllArgsConstructor
@Builder
@Data
@Entity
@Table(name = "user_student2")
@Accessors(chain = true)
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
public class Student2 {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@EqualsAndHashCode.Include
private Long id;
@Column(length = 25, nullable = false)
private String name;
@Column(length = 50, nullable = false)
private String address;
@Embedded
@AttributeOverrides({
@AttributeOverride(name = "name", column = @Column(name = "contacts_name", length = 25)),
@AttributeOverride(name = "address", column = @Column(name = "contacts_address", length = 50)),
@AttributeOverride(name = "phone", column = @Column(name = "contacts_phone", length = 15))
})
private Contacts contacts;
public Student2() {
}
}
这里的@Embeddable
注解表明该类可以被“嵌入”到一个实体类中,充当某些字段的映射。@Embedded
注解表明这里嵌入了一个用@Embeddable
标记的类。
就像以前学习 MyBastis 时在一个 MapperSet 中嵌入另一个 MapperSet 时需要指定字段映射关系,这里同样需要指定,这体现在 @AttributeOverrides
注解中包含的多条@AttributeOverride
注解。其name
属性表示的是被嵌入的类型的属性名称,column
属性表示的是对应的数据库表结构中的字段信息。
如果缺省
@AttributeOverrides
和@AttributeOverride
注解,默认会用被嵌入的类型(这里是Contacts
)的属性名称作为表结构字段名进行映射。但显然这里是行不通的,会报错(因为联系人的姓名与学生的姓名都会映射到同一个name
字段)。
现在实体类变得更加“结构化”,这点在测试用例中构建新对象时体现的很明显:
@Test
@SneakyThrows
void testAddNewStudent() {
Student2 newStudent = Student2.builder()
.address("宁安大街101号")
.name("icexmoon")
.contacts(Contacts.builder()
.name("lalala")
.address("北京东路100号")
.phone("123456789")
.build())
.build();
student2Repository.save(newStudent);
Assertions.assertNotNull(newStudent.getId());
ObjectMapper om = new ObjectMapper();
var json = om.writeValueAsString(newStudent);
System.out.println(json);
}
输出的 JSON 串也能更清楚地观察到结构化的好处。
The End,谢谢阅读。文章来源:https://www.toymoban.com/news/detail-523935.html
本文的完整示例代码可以从这里获取。文章来源地址https://www.toymoban.com/news/detail-523935.html
参考资料
- Jpa @Embedded and @Embeddable | Baeldung
到了这里,关于从零开始 Spring Boot 52:@Embedded 和 @Embeddable的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!