2010-11-08 93 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