2

Hibernateを使用したJavaでのStateパターンの実装を検索し、状況に新しい状態を追加する柔軟な方法を提供するために、列挙型を使用したソリューションへの参照をいくつか見つけました。

ここでのソリューションが気に入りました。ここでは、ConcreteStateクラス名が保存されているテーブルフィールド「state」の値から状態オブジェクトを作成するためにリフレクションが使用されます:http://nerdboys.com/2007/06/08/state-pattern -persistence-with-hibernate /

ただし、整数値を保持するのとは対照的に、DBにcom.myCompany.myProject.asdasd.ConcreteState型の文字列値を保持するとスペースが無駄になるため、このソリューションは推奨されませんでした。したがって、次のようなテーブルに可能な状態を保存する方法があるかどうか疑問に思います。

customer_states(PK id INT、className VARCHAR)

そして、次のようにFKを状態にするために、customersテーブルを変更します。

顧客(PK id INT、name VARCHAR、FK state INT)

したがって、必要以上にディスクスペースを使用することはなく、顧客の状態の一貫性を維持して、状況に新しい状態を簡単に追加できるようにします...しかし、これをUserTypeにどのように実装しますか?

ありがとう!

4

2 に答える 2

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;
    }
}
于 2010-11-08T13:38:55.697 に答える
0

列挙型を格納するデータベースとしてMySQLを使用していると仮定すると、列挙型の値は文字列ではなく数値として格納されます。したがって、列挙型を使用する場合と整数FKを使用する場合では、スペースを失うことはありません。MySQLはどのように列挙型を保存しますか?を参照してください。

列挙型は、別のテーブルを作成してFKを介して参照するのではなく、使いやすいのでエレガントです。それらがアプリケーションロジックを参照している場合は、データ(つまり、テーブル内の行)の一部としてではなく、スキーマ/プログラムの一部としてそれらを使用する方が適切です。http://www.databasesandlife.com/mysqls-enum-datatype-is-a-good-thing/を参照してください

Hibernateで列挙型を使用する方法については、ここを参照してください。(これがはるかに簡単だったらいいのにと思います。Hibernateがそのまま列挙型をサポートしない理由がわかりません)。 http://community.jboss.org/wiki/UserTypeforpersistingaTypesafeEnumerationwithaVARCHARcolumn

于 2010-11-08T13:41:55.773 に答える