简体   繁体   English

使用hibernate注释将枚举映射到表

[英]Mapping enum to a table with hibernate annotation

I have a table DEAL and a table DEAL_TYPE. 我有一个表DEAL和一个表DEAL_TYPE。 I would like to map this code: 我想映射这段代码:

public class Deal {
   DealType type;
}

public enum DealType {
   BASE("Base"), EXTRA("Extra");
}

The problem is that the data already exist in the database. 问题是数据已存在于数据库中。 And I'm having a hard time mapping the classes to the database. 而且我很难将类映射到数据库。

The database looks something like that: 数据库看起来像这样:

   TABLE DEAL {
      Long id;
      Long typeId;
   }

   TABLE DEAL_TYPE {
       Long id;
       String text;
   }

I know I could use a simple @OneToMany relationship from deal to deal type, but I would prefer to use an enum. 我知道我可以使用简单的@OneToMany关系从交易到交易类型,但我更喜欢使用枚举。 Is this possible? 这可能吗?

I almost got it working by using a EnumType.ORDINAL type. 我几乎使用EnumType.ORDINAL类型工作。 But unfortunately, my IDs in my deal type table are not sequential, and do not start at 1. 但不幸的是,我的交易类型表中的ID不是顺序的,并且不是从1开始。

Any suggestions? 有什么建议?

Hibernate is kind of terrible at Enums. Hibernate在Enums中有点可怕。 It's a strange failing of an otherwise pretty good ORM. 这是一个奇怪的失败,否则相当不错的ORM。 The "easiest" way to get around it is to declare your Enum a custom hibernate type. 解决它的“最简单”方法是将Enum声明为自定义休眠类型。 Fortunately, Hibernate wrote an example implementation which you can crib verbatim into your app: 幸运的是,Hibernate编写了一个示例实现,您可以将其逐字记录到您的应用程序中:

http://www.hibernate.org/265.html http://www.hibernate.org/265.html

They even include instructions on how to use it. 他们甚至包括如何使用它的说明。 This is the pattern I use whenever I end up with the need to persist enums. 这是我在最终需要持久化枚举时使用的模式。

I've created a similar class like the one suggested by hibernate only that is configurable and there is no need to create a new type only for this persistence. 我创建了一个类似于hibernate所建议的类,它是可配置的,不需要为这个持久性创建一个新类型。

Can be used like 可以像

@Type(type = "ro.raisercostin.hibernate.EnumUserType", parameters = @Parameter(name = "type", value = "DealType"))
DealType dealType;

I added an implementation of ParameterizedType to support the passed parameter. 我添加了ParameterizedType的实现来支持传递的参数。

public class EnumUserType implements UserType, ParameterizedType {

    private static final int[] SQL_TYPES = { Types.VARCHAR };
    private Class clazz = null;

    public EnumUserType() {
    }

    @Override
    public void setParameterValues(Properties parameters) {
        String className = (String) parameters.get("type");
        try {
            this.clazz = Class.forName(className);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException("Couldn't get the class for name [" + className + "].", e);
        }
    }

    public int[] sqlTypes() {
        return SQL_TYPES;
    }

    public Class returnedClass() {
        return clazz;
    }

    public Object nullSafeGet(ResultSet resultSet, String[] names, Object owner) throws HibernateException,
            SQLException {
        String name = resultSet.getString(names[0]);
        Object result = null;
        if (!resultSet.wasNull()) {
            result = Enum.valueOf(clazz, name);
        }
        return result;
    }

    public void nullSafeSet(PreparedStatement preparedStatement, Object value, int index) throws HibernateException,
            SQLException {
        if (null == value) {
            preparedStatement.setNull(index, Types.VARCHAR);
        } else {
            preparedStatement.setString(index, ((Enum) value).name());
        }
    }

    public Object deepCopy(Object value) throws HibernateException {
        return value;
    }

    public boolean isMutable() {
        return false;
    }

    public Object assemble(Serializable cached, Object owner) throws HibernateException {
        return cached;
    }

    public Serializable disassemble(Object value) throws HibernateException {
        return (Serializable) value;
    }

    public Object replace(Object original, Object target, Object owner) throws HibernateException {
        return original;
    }

    public int hashCode(Object x) throws HibernateException {
        return x.hashCode();
    }

    public boolean equals(Object x, Object y) throws HibernateException {
        if (x == y) {
            return true;
        }
        if ((null == x) || (null == y)) {
            return false;
        }
        return x.equals(y);
    }
}

You could annotate the enum with @Entity and use a custoumn tuplizer to create the instances of the enum with Enum.valueOf 你可以用注释的枚举@Entity并使用custoumn的tuplizer创建与枚举的例子Enum.valueOf

The enum declaration then looks like: 然后枚举声明如下:

@Entity
@Table(name = "node_interface_type")
@Tuplizer(impl = EnumTuplizer.class)
public enum Type {
    WIRED, WIRELESS, WIRELESS_SENSOR_NODE;
    @Id
    public String name = toString();
}

And the Tuplizer is: Tuplizer是:

public class EnumTuplizer extends PojoEntityTuplizer {
    public EnumTuplizer(EntityMetamodel entityMetamodel, PersistentClass mappedEntity) {
        super(entityMetamodel, mappedEntity);
    }

    @Override
    protected Instantiator buildInstantiator(final PersistentClass persistentClass) {
        return new Instantiator() {
            @Override
            public Object instantiate(Serializable id) {
                try {
                    return Enum.valueOf(
                            (Class) persistentClass.getClass().getClassLoader().loadClass(persistentClass.getClassName()),
                            (String) id
                    );
                } catch (ClassNotFoundException e) {
                    throw new AssertionError(e);
                }
            }

            @Override
            public Object instantiate() {
                throw new UnsupportedOperationException();
            }

            @Override
            public boolean isInstance(Object object) {
                throw new UnsupportedOperationException();
            }
        };
    }
}

If you want to use the entity just read-only, then you can use @Formula and @Enumerated . 如果您只想使用只读实体,那么您可以使用@Formula@Enumerated Try something like: 尝试类似的东西:

@Entity
public class Deal {
   @Formula("(select text from DEAL_TYPE dt where dt.id = typeId)")
   @Enumerated(EnumType.STRING)
   DealType type;
}

虽然远非理想,但我对此问题的解决方案是使用EnumStringType和非规范化可更新视图。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM