红茶的个人站点

  • 首页
  • 专栏
  • 开发工具
  • 其它
  • 隐私政策
Awalon
Talk is cheap,show me the code.
  1. 首页
  2. 专栏
  3. Spring Boot 学习笔记
  4. 正文

从零开始 Spring Boot 52:@Embedded 和 @Embeddable

2023年6月30日 1120点热度 0人点赞 0条评论

spring boot

图源:简书 (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 串也能更清楚地观察到结构化的好处。

除了上述的典型用途之外,还可以用@Embedded标记的类定义联合主键,具体可以查看这篇文章。

The End,谢谢阅读。

本文的完整示例代码可以从这里获取。

参考资料

  • Jpa @Embedded and @Embeddable | Baeldung

本作品采用 知识共享署名 4.0 国际许可协议 进行许可
标签: embedable embedded jpa
最后更新:2023年7月1日

魔芋红茶

加一点PHP,加一点Go,加一点Python......

点赞
< 上一篇
下一篇 >

文章评论

取消回复

*

code

COPYRIGHT © 2021 icexmoon.cn. ALL RIGHTS RESERVED.
本网站由提供CDN加速/云存储服务

Theme Kratos Made By Seaton Jiang

宁ICP备2021001508号

宁公网安备64040202000141号