Паттерн состояния и Hibernate без Enum - PullRequest
2 голосов
/ 08 ноября 2010

Я искал реализацию шаблона State в Java с помощью Hibernate и нашел несколько ссылок на решение, использующее Enums, чтобы обеспечить гибкий способ добавления новых состояний в ситуацию.

Мне понравилось решение здесь, где отражение используется для создания объекта состояния из значения поля таблицы "state", в котором сохраняется имя класса ConcreteState: http://nerdboys.com/2007/06/08/state-pattern-persistence-with-hibernate/

Но это решение не рекомендуется, так как хранение значения String типа com.myCompany.myProject.asdasd.ConcreteState в БД будет пустой тратой пространства, в отличие от целочисленного значения. Поэтому мне интересно, есть ли способ сохранить возможные состояния в таблице, например:

customer_states (PK ID INT, className VARCHAR)

И измените таблицу моих клиентов, чтобы получить FK для состояния, например:

клиенты (PK id INT, имя VARCHAR, FK state INT)

Так что я не буду использовать больше дискового пространства, чем нужно, и я бы поддерживал согласованность состояний клиентов, чтобы было легко добавить новое состояние в ситуацию ... Но как бы вы реализовали это в своем типе пользователя? ??

Спасибо!

Ответы [ 2 ]

0 голосов
/ 08 ноября 2010

Если вы используете MySQL в качестве базы данных для хранения ваших перечислений, значения перечислений хранятся как числа, а не как строки. Таким образом, вы не теряете место, используя перечисление против использования целого числа FK. См. Как перечисляет MySQL Store?

Перечисления изящны , поскольку они просты в использовании против создания другой таблицы и последующего обращения к ней через FK. Если они ссылаются на логику приложения, лучше иметь их как часть схемы / программы, а не как часть данных (то есть строк в таблице). Смотри http://www.databasesandlife.com/mysqls-enum-datatype-is-a-good-thing/

Смотрите здесь, как использовать перечисления с Hibernate . (Хотелось бы, чтобы это было намного проще, я не понимаю, почему Hibernate не поддерживает Enums "из коробки"). http://community.jboss.org/wiki/UserTypeforpersistingaTypesafeEnumerationwithaVARCHARcolumn

0 голосов
/ 08 ноября 2010

Отображение гибернации может быть:

<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>

Перечисление Status

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;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...