Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/349.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 将枚举映射到具有hibernate注释的表_Java_Hibernate_Enums_Orm - Fatal编程技术网

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

Java 将枚举映射到具有hibernate注释的表,java,hibernate,enums,orm,Java,Hibernate,Enums,Orm,我有桌上交易和桌上交易类型。我想映射此代码: public class Deal { DealType type; } public enum DealType { BASE("Base"), EXTRA("Extra"); } 问题是数据库中已经存在数据。我很难将这些类映射到数据库 数据库看起来像这样: TABLE DEAL { Long id; Long typeId; } TABLE DEAL_TYPE { Long

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

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开始的


有什么建议吗?

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


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

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

我创建了一个类似于hibernate建议的类,它是可配置的,并且不需要为这个持久性创建新类型

可以像这样使用

@Type(type = "ro.raisercostin.hibernate.EnumUserType", parameters = @Parameter(name = "type", value = "DealType"))
DealType dealType;
我添加了ParameteredType的实现来支持传递的参数

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);
    }
}

您可以使用
@Entity
注释枚举,并使用custoumn tuplizer使用
enum.valueOf

enum声明如下所示:

@Entity
@Table(name = "node_interface_type")
@Tuplizer(impl = EnumTuplizer.class)
public enum Type {
    WIRED, WIRELESS, WIRELESS_SENSOR_NODE;
    @Id
    public String name = toString();
}
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();
            }
        };
    }
}

如果要使用只读实体,则可以使用
@公式
@枚举
。尝试以下方法:

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

是的,我一直不明白为什么他们没有更好的解决方案。但是你在哪里定义枚举的id列和文本列?我不明白如何将枚举映射到一个单独的带有id和描述的表。您能否给出一个代码示例,说明如何在Hibernate注释中实现这一点?这是@Naor提出的问题。这个答案已经过时了,我们现在可以使用它了,似乎Hibernate在两个方法上扩展了签名,但在其他方面,这对我来说很好。有没有想过把它贡献给Hibernate项目?@raisercostin,我正在尝试你上面解释的东西。我不确定注释中的参数值是什么。请你详细说明一下,或者指出我可以获得更多信息的来源。现在我明白了。参数类似于type:DealType,其中type是使用的键EnumUserType,value是类(使用完整的类名,包括包)。我认为现在可以使用@Enumeratedyou's life saver来摆脱Tuplizer。有了这个,我可以将hibernate对象恢复为带有自定义值的枚举,并在repositories中使用它们,这不是一个糟糕的解决方案,因为您也考虑过插入和更新。这里的其他一些解决方案可能只是为了阅读。虽然这只适用于少数数据库,如Oracle。虽然我在MSSQL上实现了这一点,可更新视图非常简单,但在大多数RDBMS系统上通过在视图上放置“而不是”触发器来修改基础表,应该可以进行模拟。