在JPA中使用带自定义属性的枚举作为ID时遇数据转换异常
问题:自定义枚举作为JPA实体ID时查询抛出类型转换异常
实体与Repository定义
我定义了如下JPA实体,使用自定义枚举作为ID字段:
public class Entity { @Id @Column(name = "id") private EntityId id; @RequiredArgsConstructor public enum EntityId { A("a"), B("b"), C("c"), D("d"); @Getter private final String id; } }
对应的Repository接口:
public interface EntityRepository extends JpaRepository<Entity, Entity.EntityId> { }
异常信息
调用EntityRepository#findAll时抛出异常,核心栈信息如下:
org.springframework.dao.DataIntegrityViolationException: could not execute query; SQL [select entity0_.id as id_1_2_ from entity entity0_]; ... Caused by: org.hibernate.exception.DataException: could not execute query ... Caused by: org.h2.jdbc.JdbcSQLDataException: Data conversion error converting "b" [22018-200] ... Caused by: java.lang.NumberFormatException: For input string: "b"
背景说明
- 已创建对应
AttributeConverter<Entity.EntityId, String>,但问题未解决 - 若移除枚举中的
id属性并使用@Enumerated(STRING)可正常运行,但业务要求必须保留该属性 - 数据库表ID为字符串类型,存储值为"a"、"b"、"c"、"d",无法使用枚举的ordinal或name映射(枚举名是"A"、"B"等,与存储值不匹配)
解决方案
1. 正确实现并注册AttributeConverter
确保转换器类添加@Converter注解,实现正确的双向转换逻辑:
import javax.persistence.AttributeConverter; import javax.persistence.Converter; import java.util.Arrays; @Converter(autoApply = true) // 自动应用到所有Entity.EntityId类型的属性 public class EntityIdConverter implements AttributeConverter<Entity.EntityId, String> { @Override public String convertToDatabaseColumn(Entity.EntityId entityId) { return entityId != null ? entityId.getId() : null; } @Override public Entity.EntityId convertToEntityAttribute(String dbValue) { return dbValue != null ? Arrays.stream(Entity.EntityId.values()) .filter(id -> id.getId().equals(dbValue)) .findFirst() .orElseThrow(() -> new IllegalArgumentException("无效的ID值: " + dbValue)) : null; } }
2. 让枚举实现Serializable接口
JPA要求ID类型必须可序列化,因此需要给枚举添加Serializable实现:
@RequiredArgsConstructor public enum EntityId implements Serializable { // 添加Serializable接口 A("a"), B("b"), C("c"), D("d"); @Getter private final String id; }
3. (可选)手动指定转换器
如果autoApply = true未生效,可在实体的ID字段上手动关联转换器:
@Id @Column(name = "id") @Convert(converter = EntityIdConverter.class) // 手动指定转换器 private EntityId id;
内容的提问来源于stack exchange,提问作者thmasker
相关产品推荐
相关产品推荐

