1

我想问几个关于 Hibernate/jpa 数据持久性的问题。所以这是我的两个主要问题:

1)我使用hibernate使用通用用户类型和tuplizer来持久化枚举,这是我的示例代码:


通用枚举持久性类型:

import javax.persistence.Cacheable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;

import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;

import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.hibernate.annotations.Tuplizer;

import com.jimmy.htf.util.GenericEnumTuplizer;

@Entity
@Cacheable
@Tuplizer(impl = GenericEnumTuplizer.class)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
public enum Language  {

    ARABIC(1, "language.arabic"), BULGARIAN(2, "language.bulgarian"), CATALAN(3, "language.catalan"), CHINESE(4, "language.chinese"), CROATIAN(5, "language.croatian"), CZECH(6, "language.czech"),
    DANISH(7, "language.danish"), DUTCH(8, "language.dutch"), ENGLISH(9, "language.english"), FINNISH(10, "language.finnish"), FRENCH(11, "language.french"), GERMAN(12, "language.german"),
    GREEK (13, "language.greek"), HEBREW(14, "language.hebrew"), HUNGARIAN(15, "language.hungarian"), INDONESIAN(16, "language.indonesian"), ITALIAN(17, "language.italian"), 
    JAPANESE(18, "language.japanese"), KOREAN(19, "language.korean"), LITHUANIAN(20, "language.lithuanian"), NORWEGIAN(21, "language.norwegian"), PERSIAN(22, "language.persian"), 
    POLISH(23, "language.polish"), PORTUGUESE(24, "language.portuguese"), ROMANIAN(25, "language.romanian"), RUSSIAN(26, "language.russian"), SERBIAN(27, "language.serbian"), 
    SLOVAK(28, "language.slovak"), SLOVENIAN(29, "language.slovenian"), SPANISH(30, "language.spanish"), SWEDISH(31, "language.swedish"), TURKISH(32, "language.turkish"),
    THAI(33, "language.thai"), UKRAINIAN(34, "language.ukrainian"), VIETNAMESE(35, "language.vietnamese"), OTHER(36, "language.other");

    @Id
    @Getter
    private Integer codeValue;

    @Getter
    @Column(length = 64)
    private String  I18nGlobalMessage;

    public static Language fromValue(Integer value) {
        switch (value) {
            case 1: return ARABIC; 
            case 2: return BULGARIAN;
            case 3: return CATALAN;
            case 4: return CHINESE;
            case 5: return CROATIAN;
            case 6: return CZECH;
            case 7: return DANISH;
            case 8: return DUTCH;
            case 9: return ENGLISH;
            case 10: return FINNISH;
            case 11: return FRENCH;
            case 12: return GERMAN;
            case 13: return GREEK;
            case 14: return HEBREW;
            case 15: return HUNGARIAN;
            case 16: return INDONESIAN;
            case 17: return ITALIAN;
            case 18: return JAPANESE;
            case 19: return KOREAN;
            case 20: return LITHUANIAN;
            case 21: return NORWEGIAN;
            case 22: return PERSIAN;
            case 23: return POLISH;
            case 24: return PORTUGUESE;
            case 25: return ROMANIAN;
            case 26: return RUSSIAN;
            case 27: return SERBIAN;
            case 28: return SLOVAK;
            case 29: return SLOVENIAN;
            case 30: return SPANISH;
            case 31: return SWEDISH;
            case 32: return TURKISH;
            case 33: return THAI;
            case 34: return UKRAINIAN;
            case 35: return VIETNAMESE;
            case 36: return OTHER;
            default: return null;
        }
    }
}

通用枚举元组器

import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import org.hibernate.mapping.PersistentClass;
import org.hibernate.tuple.Instantiator;
import org.hibernate.tuple.entity.EntityMetamodel;
import org.hibernate.tuple.entity.PojoEntityTuplizer;

public class GenericEnumTuplizer extends PojoEntityTuplizer {

    public GenericEnumTuplizer(EntityMetamodel entityMetamodel, PersistentClass mappedEntity) {
        super(entityMetamodel, mappedEntity);
    }

    @Override
    @SuppressWarnings(value = { "unchecked", "rawtypes"})
    protected Instantiator buildInstantiator(final PersistentClass persistentClass) {
        return new Instantiator() {
            @Override
            public Object instantiate(Serializable id) {
                try {
                    Class enumClass = getMappedClass();
                    String identifierMethodName = GenericEnumPersistenceType.DEFAULT_CODE_VALUE_METHOD_NAME;
                    Method codeValueMethod = enumClass.getMethod(identifierMethodName, new Class[0]);
                    Class<?> codeValueType = codeValueMethod.getReturnType();
                    String valueOfMethodName = GenericEnumPersistenceType.DEFAULT_FROM_VALUE_METHOD_NAME;
                    Method fromValueMethod = enumClass.getMethod(valueOfMethodName, new Class[] { codeValueType });
                    return fromValueMethod.invoke(enumClass, id); 
                } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
                    throw new AssertionError(e);
                }
            }

            @Override
            public Object instantiate() {
                throw new UnsupportedOperationException();
            }

            @Override
            public boolean isInstance(Object object) {
                throw new UnsupportedOperationException();
            }
        };
    }
}

通用枚举持久性类型

import java.io.Serializable;
import java.lang.reflect.Method;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Properties;

import org.apache.commons.lang.ObjectUtils;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.type.IntegerType;
import org.hibernate.usertype.ParameterizedType;
import org.hibernate.usertype.UserType;

public class GenericEnumPersistenceType<E> implements UserType, ParameterizedType {
    public static final String DEFAULT_CODE_VALUE_METHOD_NAME = "getCodeValue";
    public static final String DEFAULT_FROM_VALUE_METHOD_NAME = "fromValue";
    private Method codeValueMethod;
    private Method fromValueMethod;
    private Class<?> codeValueType;
    private Class<E> enumClass; 

    public GenericEnumPersistenceType(){}

    @Override
    @SuppressWarnings("unchecked")
    public void setParameterValues(Properties parameters) {
        String enumClassName = parameters.getProperty("enumClass");
        try {
            enumClass =  (Class<E>) Class.forName(enumClassName).asSubclass(Enum.class);
        } catch (ClassNotFoundException e) {
            throw new HibernateException("Enum class not found", e);
        }
        String identifierMethodName = parameters.getProperty("codeValueMethod", DEFAULT_CODE_VALUE_METHOD_NAME);
        try {
            codeValueMethod = enumClass.getMethod(identifierMethodName, new Class[0]);
            codeValueType = codeValueMethod.getReturnType();
        } catch (Exception e) {
            throw new HibernateException("Failed to obtain codeValue method. Setting default method name", e);
        }
        String valueOfMethodName = parameters.getProperty("fromValueMethod", DEFAULT_FROM_VALUE_METHOD_NAME);
        try {
            fromValueMethod = enumClass.getMethod(valueOfMethodName, new Class[] { codeValueType });
        } catch (Exception e) {
            throw new HibernateException("Failed to obtain fromValue method. Setting default method name", e);
        }
    }

    @Override
    public Object nullSafeGet(ResultSet resultSet, String[] names, SessionImplementor session, Object owner) throws HibernateException, SQLException {
        try {
            String propertyValue = resultSet.getString(names[0]);
            Integer propertyNumericValue;
            try {
                propertyNumericValue = Integer.valueOf(propertyValue);
            } catch (NumberFormatException e) {
                return null;
            }
            return fromValueMethod.invoke(enumClass, propertyNumericValue); 
        } catch (Exception e) {
            e.printStackTrace();
            throw new HibernateException("Exception while invoking valueOf method '" + fromValueMethod.getName() + "' of " + "enumeration class '" + enumClass + "'", e);
        }
    }

    @Override
    public void nullSafeSet(PreparedStatement preparedStatement, Object value, int index, SessionImplementor session) throws HibernateException, SQLException {
        try {
            if (null == value) {
                preparedStatement.setNull(index, Types.INTEGER);
            } else {
                Object identifier = codeValueMethod.invoke(value, new Object[0]);
                preparedStatement.setInt(index, (Integer) identifier);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new HibernateException("Exception while invoking identifier method '" + codeValueMethod.getName() + "' of " + "enumeration class '" + enumClass + "'", e);
        }

    }

    @Override
    public Class<E> returnedClass() {
        return enumClass;
    }

    @Override
    public int[] sqlTypes() {
         return new int[] { IntegerType.INSTANCE.sqlType() };
    }

    @Override
    public boolean isMutable() {
        return false;
    }

    @Override
    public boolean equals(Object x, Object y) throws HibernateException {
        return ObjectUtils.equals(x, y);
    }

    @Override
    public int hashCode(Object x) throws HibernateException {
        assert (x != null);
        return x.hashCode();
    }

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

    @Override
    public Object replace(Object original, Object target, Object owner) throws HibernateException {
        return original;
    }

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

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

}

现在好了,这门课一切正常。我需要做一些改进:

因为我的枚举和数据库表中也有我的语言:

----> 语言[] 语言 = Language.values(); (语言是上面枚举的名称)

我想直接从我的枚举中使用对象,而不从数据库中检索实体:换句话说,我想这样做:

设置 speakLanguages = new HashSet(); 口语语言.add(语言.英语);订阅

r.setSpokenLanguages(speaknLanguages);

而不是这样做:

设置 speakLanguages = new HashSet(); speakLanguages.add(languageService.getLanguageById(Language.ENGLISH.getCodeValue())); 订阅

r.setSpokenLanguages(speaknLanguages);

我想绕过 dao 使用和数据库访问,但每次我这样做时都会出现异常,因为元素已插入 DB 并且 id 显然已经存在。

即使 Id 不是自动生成的,如果它没有从 DB 中检索,Hibernate 仍然会插入元素。所以我想知道是否有办法处理这种情况,或者是否有一个解决方案可以像一个类一样在启动时初始化整个应用程序并从 DB 而不是从 Enum 加载语言列表。

2)

我正在使用 JPA 2.0 映射。使用 hibernate-jpa-2.0 和 hibernate 4.1.0.final

我的两个班级之间有@ManyToOne 关系:EventPicture --> Event

    @ManyToOne
@JoinColumn(name = "event")
@ForeignKey(name = "event_foreign_Key")
private Event event;

event 是 eventPicture 中的私有属性,用于映射拥有事件,我收到了我不明白的消息,我做了一些研究,但没有发现任何相关信息;

 Foreign key "{0}" not found in the table "{1}"

任何帮助,将不胜感激。谢谢

4

0 回答 0