将 Java enums 映射到 basic value types 有几种方式
- 使用 @Enumerated / @MapKeyEnumerated(for map keys annotations) 和 javax.persistence.EnumType
- 使用 @Convert 和 AttributeConverter
- 使用 Custom type
JPA 不允许同时使用 @Enumerated 和 AttributeConverter 。
EnumType.ORDINAL
package org.example.demo.hibernate;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Persistence;
public class Test {
public static void main(String[] args) {
EntityManagerFactory factory = Persistence.createEntityManagerFactory("test");
EntityManager em = factory.createEntityManager();
Phone phone = new Phone();
phone.type = PhoneType.LAND_LINE;
em.getTransaction().begin();
em.persist(phone);
em.getTransaction().commit();
em.clear();
Phone p = em.find(Phone.class, phone.id);
// LAND_LINE
System.out.println(p.type);
em.close();
factory.close();
}
@Entity(name = "Phone")
public static class Phone {
@Id
@GeneratedValue
Integer id;
@Enumerated(EnumType.ORDINAL)
private PhoneType type;
}
public enum PhoneType {
LAND_LINE, MOBILE;
}
}
生成的 SQL
drop table if exists Phone cascade
drop sequence if exists hibernate_sequence
create sequence hibernate_sequence start 1 increment 1
create table Phone (id int4 not null, type int4, primary key (id))
select nextval ('hibernate_sequence')
insert into Phone (type, id) values (0, 1)
select test_phone0_.id as id1_0_0_, test_phone0_.type as type2_0_0_ from Phone test_phone0_ where test_phone0_.id=1
EnumType.STRING
package org.example.demo.hibernate;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Persistence;
public class Test {
public static void main(String[] args) {
EntityManagerFactory factory = Persistence.createEntityManagerFactory("test");
EntityManager em = factory.createEntityManager();
Phone phone = new Phone();
phone.type = PhoneType.LAND_LINE;
em.getTransaction().begin();
em.persist(phone);
em.getTransaction().commit();
em.clear();
Phone p = em.find(Phone.class, phone.id);
// LAND_LINE
System.out.println(p.type);
em.close();
factory.close();
}
@Entity(name = "Phone")
public static class Phone {
@Id
@GeneratedValue
Integer id;
@Enumerated(EnumType.STRING)
private PhoneType type;
}
public enum PhoneType {
LAND_LINE, MOBILE;
}
}
生成的 SQL
drop table if exists Phone cascade
drop sequence if exists hibernate_sequence
create sequence hibernate_sequence start 1 increment 1
create table Phone (id int4 not null, type varchar(255), primary key (id))
select nextval ('hibernate_sequence')
insert into Phone (type, id) values ('LAND_LINE', 1)
select test_phone0_.id as id1_0_0_, test_phone0_.type as type2_0_0_ from Phone test_phone0_ where test_phone0_.id=1
AttributeConverter
package org.example.demo.hibernate;
import javax.persistence.AttributeConverter;
import javax.persistence.Convert;
import javax.persistence.Converter;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Persistence;
public class Test {
public static void main(String[] args) {
EntityManagerFactory factory = Persistence.createEntityManagerFactory("test");
EntityManager em = factory.createEntityManager();
Person person = new Person();
person.gender = Gender.MALE;
em.getTransaction().begin();
em.persist(person);
em.getTransaction().commit();
em.clear();
Person p = em.find(Person.class, person.id);
// MALE
System.out.println(p.gender);
em.close();
factory.close();
}
@Entity(name = "Person")
public static class Person {
@Id
@GeneratedValue
Long id;
String name;
@Convert(converter = GenderConverter.class)
Gender gender;
}
@Converter
public static class GenderConverter implements AttributeConverter<Gender, Character> {
public Character convertToDatabaseColumn(Gender value) {
if (value == null) {
return null;
}
return value.getCode();
}
public Gender convertToEntityAttribute(Character value) {
if (value == null) {
return null;
}
return Gender.fromCode(value);
}
}
public enum Gender {
MALE('M'), FEMALE('F');
private final char code;
Gender(char code) {
this.code = code;
}
public static Gender fromCode(char code) {
if (code == 'M' || code == 'm') {
return MALE;
}
if (code == 'F' || code == 'f') {
return FEMALE;
}
throw new UnsupportedOperationException("The code " + code + " is not supported!");
}
public char getCode() {
return code;
}
}
}
生成的 SQL
drop table if exists Person cascade
drop sequence if exists hibernate_sequence
create sequence hibernate_sequence start 1 increment 1
create table Person (id int8 not null, gender char(1), name varchar(255), primary key (id))
select nextval ('hibernate_sequence')
insert into Person (gender, name, id) values ('M', NULL, 1)
select test_perso0_.id as id1_0_0_, test_perso0_.gender as gender2_0_0_, test_perso0_.name as name3_0_0_ from Person test_perso0_ where test_perso0_.id=1
Custom type
package org.example.demo.hibernate;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Persistence;
import org.hibernate.annotations.Type;
import org.hibernate.type.AbstractSingleColumnStandardBasicType;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.AbstractTypeDescriptor;
import org.hibernate.type.descriptor.java.CharacterTypeDescriptor;
import org.hibernate.type.descriptor.sql.CharTypeDescriptor;
public class Test {
public static void main(String[] args) {
EntityManagerFactory factory = Persistence.createEntityManagerFactory("test");
EntityManager em = factory.createEntityManager();
Person person = new Person();
person.gender = Gender.MALE;
em.getTransaction().begin();
em.persist(person);
em.getTransaction().commit();
em.clear();
Person p = em.find(Person.class, person.id);
// MALE
System.out.println(p.gender);
em.close();
factory.close();
}
@Entity(name = "Person")
public static class Person {
@Id
@GeneratedValue
Long id;
String name;
@Type(type = "org.example.demo.hibernate.Test$GenderType")
Gender gender;
}
@SuppressWarnings("serial")
public static class GenderType extends AbstractSingleColumnStandardBasicType<Gender> {
public static final GenderType INSTANCE = new GenderType();
public GenderType() {
super(CharTypeDescriptor.INSTANCE, GenderJavaTypeDescriptor.INSTANCE);
}
public String getName() {
return "gender";
}
@Override
protected boolean registerUnderJavaType() {
return true;
}
}
@SuppressWarnings("serial")
public static class GenderJavaTypeDescriptor extends AbstractTypeDescriptor<Gender> {
public static final GenderJavaTypeDescriptor INSTANCE = new GenderJavaTypeDescriptor();
protected GenderJavaTypeDescriptor() {
super(Gender.class);
}
public String toString(Gender value) {
return value == null ? null : value.name();
}
public Gender fromString(String string) {
return string == null ? null : Gender.valueOf(string);
}
public <X> X unwrap(Gender value, Class<X> type, WrapperOptions options) {
return CharacterTypeDescriptor.INSTANCE.unwrap(value == null ? null : value.getCode(), type, options);
}
public <X> Gender wrap(X value, WrapperOptions options) {
return Gender.fromCode(CharacterTypeDescriptor.INSTANCE.wrap(value, options));
}
}
public enum Gender {
MALE('M'), FEMALE('F');
private final char code;
Gender(char code) {
this.code = code;
}
public static Gender fromCode(char code) {
if (code == 'M' || code == 'm') {
return MALE;
}
if (code == 'F' || code == 'f') {
return FEMALE;
}
throw new UnsupportedOperationException("The code " + code + " is not supported!");
}
public char getCode() {
return code;
}
}
}
生成 SQL
drop table if exists Person cascade
drop sequence if exists hibernate_sequence
create sequence hibernate_sequence start 1 increment 1
create table Person (id int8 not null, gender char(1), name varchar(255), primary key (id))
select nextval ('hibernate_sequence')
insert into Person (gender, name, id) values ('M', NULL, 1)
select test_perso0_.id as id1_0_0_, test_perso0_.gender as gender2_0_0_, test_perso0_.name as name3_0_0_ from Person test_perso0_ where test_perso0_.id=1