代码之家  ›  专栏  ›  技术社区  ›  Thierry Roy

将枚举映射到具有Hibernate注释的表

  •  27
  • Thierry Roy  · 技术社区  · 15 年前

    我有桌上交易和桌上交易类型。我要映射此代码:

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

    问题是数据库中已经存在数据。我很难将类映射到数据库。

    数据库如下所示:

       TABLE DEAL {
          Long id;
          Long typeId;
       }
    
       TABLE DEAL_TYPE {
           Long id;
           String text;
       }
    

    我知道我可以使用简单的@OneTomany关系,从交易类型到交易类型,但我更喜欢使用枚举。这有可能吗?

    我几乎用了EnumType.Ordinal类型。但不幸的是,我的交易类型表中的ID不是连续的,并且不是从1开始。

    有什么建议吗?

    5 回复  |  直到 6 年前
        1
  •  17
  •   James Dunn    6 年前

    冬眠有点可怕。这是一个很好的ORM的一个奇怪的失败。绕过它的“最简单”方法是将枚举声明为自定义的休眠类型。幸运的是,Hibernate编写了一个示例实现,您可以在应用程序中逐字输入:

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

    它们甚至包括如何使用它的说明。这是我在需要持久枚举时使用的模式。

        2
  •  13
  •   raisercostin    14 年前

    我创建了一个类似的类,比如Hibernate建议的类,它是可配置的,不需要为这个持久性创建一个新的类型。

    可以像这样使用

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

    我添加了一个参数化类型的实现来支持传递的参数。

    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);
        }
    }
    
        3
  •  6
  •   don_jones    13 年前

    可以用注释枚举 @Entity 并使用custoumn元组创建枚举的实例 Enum.valueOf

    然后,枚举声明如下所示:

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

    Tuplezer是:

    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();
                }
            };
        }
    }
    
        4
  •  3
  •   xmedeko    12 年前

    如果只想以只读方式使用实体,则可以使用 @Formula @Enumerated . 尝试以下方法:

    @Entity
    public class Deal {
       @Formula("(select text from DEAL_TYPE dt where dt.id = typeId)")
       @Enumerated(EnumType.STRING)
       DealType type;
    }
    
        5
  •  1
  •   Jeff Mc    15 年前

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