将 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

results matching ""

    No results matching ""