2010-11-08 10 views
2

我已经在Hibernate中搜索了Java中状态模式的实现,并且发现了几个对使用枚举的解决方案的引用,以便提供一种灵活的方式来添加新的状态。状态模式和没有枚举的休眠状态

我很喜欢这里的解决方案,其中反射用于创建从那里的ConcreteState类名保存在表中的字段“状态”的状态值对象:http://nerdboys.com/2007/06/08/state-pattern-persistence-with-hibernate/

但是这个解决方案感到沮丧是因为举行数据库中com.myCompany.myProject.asdasd.ConcreteState类型的字符串值将浪费空间,与保存整数值不同。所以我想如果有一种方法来保存像表可能状态:

customer_states(PK ID INT,类名VARCHAR)

并修改我的客户表,以便有一个FK的状态,像:

客户(PK ID INT,VARCHAR名,FK状态INT)

所以我不会用更多的磁盘空间比需要,我会十个分量客户状态的一致性,所以很容易添加新状态的情况......但是,你将如何在你的UserType中实现这个?

谢谢!

回答

0

假设你正在使用MySQL作为数据库来存储您的枚举,枚举值被存储为数字而不是字符串。所以你通过使用枚举 vs使用整数FK不会损失空间。请参阅How Does MySQL Store Enums?

枚举是优雅的,因为它们使用简单vs创建另一个表,然后通过FK引用它。如果它们引用应用程序逻辑,最好将它们作为模式/程序的一部分,而不是作为数据的一部分(即表中的行)。请参阅http://www.databasesandlife.com/mysqls-enum-datatype-is-a-good-thing/

请参阅此处了解如何使用枚举与Hibernate。 (我希望这很容易,我不明白为什么Hibernate不支持Enums开箱即用)。 http://community.jboss.org/wiki/UserTypeforpersistingaTypesafeEnumerationwithaVARCHARcolumn

+0

Adrian,对不起,我没有正确解释自己,但我正在寻找一种方法来避免Java Enums的用法...顺便说一句,我没有想过使用MySQL枚举,似乎是一个非常好的解决方案!但是你提到的有关Hibernate和Enums的声音听起来不太友好......无论如何,谢谢你的回答! – 2010-11-08 13:52:20

+0

是的,Hibernate连接Java枚举到MySQL枚举并不好:( – 2010-11-08 15:03:56

+1

@Joaquín个人而言,我不推荐MySQL的ENUM带或不带Hibernate,但[使用Hibernate的时候甚至更少](http:// stackoverflow。 com/questions/766299/mysql-enum-performance-advantage)。从纯粹的数据库中查看[Bill对他们说的](http://stackoverflow.com/questions/766299/mysql-enum-performance-advantage)看法。 – 2010-11-08 18:14:16

0

Hibernate映射可能是:

<property name="_Status"> 
     <column name="STATUS" sql-type="NUMBER" not-null="true"/> 
     <type name="GenericEnumUserType"> 
      <param name="enumClass">Status</param> 
      <param name="identifierMethod">getCode</param> 
      <param name="valueOfMethod">fromString</param> 
     </type> 
    </property> 

的状态枚举

public static enum Status { 
    ACTIVE(1, "Active"), 
    DELETED(2, "Deleted"), 
    INACTIVE(3, "Inactive"), 
    PASSWORD_EXPIRED(4, "Password Expired"); 

    /** Formal representation (single character code). */ 
    private int code; 
    /** Textual, human-readable description. */ 
    private String description; 

    // Needed by Hibernate to map column values to enum values 

    public static Status fromString(String code) { 
     for (Status status : Status.values()) { 
      if (status.getCode().equals(code.toUpperCase())) { 
       return status; 
      } 
     } 
     throw new IllegalArgumentException("Unknown user status: " + code); 
    } 

    Status(int code, String description) { 
     this.code = code; 
     this.description = description; 
    } 

    public int getCode() { 
     return code; 
    } 

    public String getDescription() { 
     return description; 
    } 

    @Override 
    public String toString() { 
     return getDescription(); 
    } 
} 

一般类:

public class GenericEnumUserType implements UserType, ParameterizedType { 
    private static final String DEFAULT_IDENTIFIER_METHOD_NAME = "name"; 
    private static final String DEFAULT_VALUE_OF_METHOD_NAME = "valueOf"; 

    private Class<? extends Enum> enumClass; 
    private Method identifierMethod; 
    private Method valueOfMethod; 
    private NullableType type; 
    private int[] sqlTypes; 

    public void setParameterValues(Properties parameters) { 
     String enumClassName = parameters.getProperty("enumClass"); 
     try { 
      enumClass = Class.forName(enumClassName).asSubclass(Enum.class); 
     } catch (ClassNotFoundException cfne) { 
      throw new HibernateException("Enum class not found", cfne); 
     } 

     String identifierMethodName = parameters.getProperty("identifierMethod", DEFAULT_IDENTIFIER_METHOD_NAME); 
     Class<?> identifierType; 

     try { 
      identifierMethod = enumClass.getMethod(identifierMethodName); 
      identifierType = identifierMethod.getReturnType(); 
     } catch (Exception e) { 
      throw new HibernateException("Failed to obtain identifier method", e); 
     } 

     type = (NullableType) TypeFactory.basic(identifierType.getName()); 

     if (type == null) 
      throw new HibernateException("Unsupported identifier type " + identifierType.getName()); 

     sqlTypes = new int[] { type.sqlType() }; 

     String valueOfMethodName = parameters.getProperty("valueOfMethod", DEFAULT_VALUE_OF_METHOD_NAME); 

     try { 
      valueOfMethod = enumClass.getMethod(valueOfMethodName, identifierType); 
     } catch (Exception e) { 
      throw new HibernateException("Failed to obtain valueOf method", e); 
     } 
    } 

    public Class returnedClass() { 
     return enumClass; 
    } 

    public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException { 
     Object identifier = type.get(rs, names[0]); 
     if (rs.wasNull()) { 
      return null; 
     } 

     try { 
      return valueOfMethod.invoke(enumClass, identifier); 
     } catch (Exception e) { 
      throw new HibernateException(
        "Exception while invoking valueOf method '" + valueOfMethod.getName() + "' of " + 
          "enumeration class '" + enumClass + "'", e); 
     } 
    } 

    public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException { 
     try { 
      if (value == null) { 
       st.setNull(index, type.sqlType()); 
      } else { 
       Object identifier = identifierMethod.invoke(value); 
       type.set(st, identifier, index); 
      } 
     } catch (Exception e) { 
      throw new HibernateException(
        "Exception while invoking identifierMethod '" + identifierMethod.getName() + "' of " + 
          "enumeration class '" + enumClass + "'", e); 
     } 
    } 

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

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

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

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

    public boolean equals(Object x, Object y) throws HibernateException { 
     return x == y; 
    } 

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

    public boolean isMutable() { 
     return false; 
    } 

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

谢谢Zoltan,但我正在寻找一种解决方案,以避免使用Java Enum来保存状态... – 2010-11-08 13:47:59