Hibernate JPA数据持久化和映射外键

时间:2012-04-19 10:34:33

标签: hibernate persistence

我想问一些关于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;
        }
    }
}

generic enum tuplizer

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

}

现在,这些课程的一切正常。我需要的是做一些改进:

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

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

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

设置spokenLanguages = new HashSet();     spokenLanguages.add(Language.ENGLISH);     订阅

r.setSpokenLanguages(spokenLanguages);

而不是这样做:

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

r.setSpokenLanguages(spokenLanguages);

我想绕过dao用法和数据库访问,但每次我这样做都会得到异常,因为元素已插入到数据库中并且id已经存在了。

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

2)

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

我的两个类之间有@ManyToOne关系:EventPicture - &gt;事件

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

event是eventPicture中的私有属性,用于映射拥有事件 而且我有这个我不明白的消息,我做了一些研究但却一无所获;

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

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

0 个答案:

没有答案