JPA 中@Enumerated

在Java中Enum是一种“奇葩”的存在,“奇葩”不代表没用,对于这种比较特殊的存在,hibernate会有很多种选择来完成Enum类型字段的映射,首先要说明的是在hibernate都是把Enum类型的字段映射成基本类型的字段,并且我这里不使用任何配置文件来配置映射,而是统一使用注解这种方式来完成映射。

注意本文使用的数据库是MySQL5.7,版本和数据库类型可能会有不同的结果。

首先我们要明确的是将Enum类型的字段映射到数据库中有两种方式:

  1. 一个是通过使用Enum类型实例在Enum中声明的顺序,也就是ordinal属性,通过这个序号来将Enum类型字段映射成int类型来存储;
  2. 一个是通过使用Enum类型实例中的name属性来完成映射,这里讲Enum类型映射成String类型来完成存储;

这两个属性其实都在java.lang.Enum中,这个类是所有Enum类型的父类。

1. 不使用任何注解

当不使用任何注解的时候,默认情况下是使用ordinal属性,也就是Enum类型实例在Enum中声明的顺序来完成映射的,具体情况如下:

@Entity
public class Person implements Serializable{
    private static final long serialVersionUID = 8849870114127659929L;

    @Id
    @GeneratedValue
    private Long id;

    @Column(nullable = false)
    private String name;

    @Column
    private Gender gender;

    public Person(String name, Gender gender){
        this.name = name;
        this.gender = gender;
    }

    // getter、setter
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

这里Gender就是我们的Enum类,如下:

public enum Gender {
    male("男"),
    female("女");

    private String name;
    private Gender(String name){
        this.name = name;
    }

    public String getName(){
        return this.name;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

此时看到生成的表结构如下:

这里可以看出Enum类型字段Gender**被映射成int(11)类型**,通过往里面插入一条数据看一下结果,如下:

@Test
public void testJpa(){
    personService.save(new Person("Jhon", Gender.male));
    personService.save(new Person("Lily", Gender.female));
}
  • 1
  • 2
  • 3
  • 4
  • 5

上边向数据库中插入了两条记录,personService是操作数据库的service,结果如下:

可以看出Gender.male对应的序号是0,Gender.female对应的是1,可以看出在使用ordinal属性映射时的序号是从0开始的

2. 使用@Enumerated注解

注解javax.persistence.Enumerated从名字上来看就可以明白是为了映射Enum类型的,从它的javadoc文档中可以说明:

Specifies that a persistent property or field should be persisted as a enumerated type. The Enumerated annotation may be used in conjunction with the Basic annotation, or in conjunction with the ElementCollection annotation when the element collection value is of basic type. If the enumerated type is not specified or the Enumerated annotation is not used, the EnumType value is assumed to be ORDINAL.

如果不使用该注解,就是在上面说的默认的情况是使用Enum中的ordinal属性来完成,所以关于这部分就不详细阐述了。

主要说明一下将Enum类型映射成字符串的方式,其实只是将Enum类型上的注解改为@Enumerated(EnumType.STRING)即可,如下:

@Entity
public class Person implements Serializable{
    private static final long serialVersionUID = 8849870114127659929L;

    @Id
    @GeneratedValue
    private Long id;

    @Column(nullable = false)
    private String name;

    @Column
    @Enumerated(EnumType.STRING)
    private Gender gender;

    public Person(String name, Gender gender){
        this.name = name;
        this.gender = gender;
    }

    // getter、setter
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

此时看到生成的表结构如下:

这里可以看出Enum类型字段Gender**被映射成VARCHAR(255)类型**,通过往里面插入一条数据看一下结果,如下:

@Test
public void testJpa(){
    personService.save(new Person("Jhon", Gender.male));
    personService.save(new Person("Lily", Gender.female));
}
  • 1
  • 2
  • 3
  • 4
  • 5

可以看出是插入的对应Enum类型的name属性,就是这么简单!

3. 使用AttributeConverter属性类型转换器

关于AttributeConverter<X, Y>

  • X 是实体属性的类型
  • Y 是数据库字段的类型
  • Y convertToDatabaseColumn(X) 作用:将实体属性X转化为Y存储到数据库中,即插入和更新操作时执行;
  • X convertToEntityAttribute(Y) 作用:将数据库中的字段Y转化为实体属性X,即查询操作时执行;

使用AttributeConverter可以将Enum中的属性名转换成数据库中存储的字段名,定义一个属性转换器如下:

@Converter
public class GenderConverter implements AttributeConverter<Gender, String> {

    @Override
    public String convertToDatabaseColumn(Gender attribute) {
        return attribute.getValue();
    }

    @Override
    public Gender convertToEntityAttribute(String dbData) {
        return Gender.fromString(dbData);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

所有的属性转换器需要实现AttributeConverter接口,这个接口可以将实体中的数据转换成到数据库中存储,这种方式可以用来映射实体属性,也可以用来将实体中数据加密存储到数据库中,这个转换器还需要使用@Converter注解标识出来。

下面要重写我们的Gender枚举类,如下:

public enum Gender {
    male("男"),
    female("女");

    private String value;
    private Gender(String value){
        this.value = value;
    }

    public String getValue(){
        return this.value;
    }

    public static Gender fromString(String value){
        Objects.requireNonNull(value, "value can not be null");
        Gender gender = null;
        if("男".equals(value)){
            gender = male;
        }
        else if("女".equals(value)){
            gender = female;
        }
        return gender;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

下面使用这个转换器如下:

@Entity
public class Person implements Serializable{
    private static final long serialVersionUID = 8849870114127659929L;

    @Id
    @GeneratedValue
    private Long id;

    @Column(nullable = false)
    private String name;

    @Column
    @Convert(converter = GenderConverter.class)
    private Gender gender;

    public Person(String name, Gender gender){
        this.name = name;
        this.gender = gender;
    }

    // getter、setter
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

生成的数据库结构如下:

可以看出和使用@Enumerated(EnumType.STRING)生成的类型是相同的,但是别急,看看插入的数据是怎么样的?

@Test
public void testJpa(){
    personService.save(new Person("Jhon", Gender.male));
    personService.save(new Person("Lily", Gender.female));
}
  • 1
  • 2
  • 3
  • 4
  • 5

结果如下:

可以看出插进去的数据已经不是Enum实例的name属性值了,而是我们自定义的value值。

  • 9
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
要查询`Equipment`表所有`equipmentType`等于`TypeA`的记录,您可以使用Spring Data JPA的命名规则自定义查询方法。请按照以下步骤进行操作: 首先,在`Equipment`实体类添加一个自定义查询方法,使用Spring Data JPA的命名规则来定义查询逻辑: ```java @Repository public interface EquipmentRepository extends JpaRepository<Equipment, Long> { List<Equipment> findByEquipmentType(EquipmentType equipmentType); } ``` 在上述代码,`findByEquipmentType()`方法使用了Spring Data JPA的命名规则来定义查询逻辑。根据命名规则,Spring Data JPA会自动生成查询语句,查询`Equipment`表所有`equipmentType`等于指定值的记录。 然后,在您的服务类(例如,`EquipmentService`)注入`EquipmentRepository`,并调用该方法来获取满足条件的记录: ```java @Service public class EquipmentService { private final EquipmentRepository equipmentRepository; public EquipmentService(EquipmentRepository equipmentRepository) { this.equipmentRepository = equipmentRepository; } public List<Equipment> findEquipmentsOfTypeA() { return equipmentRepository.findByEquipmentType(EquipmentType.TypeA); } } ``` 在上述代码,`findEquipmentsOfTypeA()`方法调用了`findByEquipmentType()`方法,并传入`EquipmentType.TypeA`作为参数,以获取所有满足条件的记录。 通过这种方式,您可以使用Spring Data JPA和基于命名规则的查询方法来查询`Equipment`表所有`equipmentType`等于`TypeA`的记录。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值