Hibernate/jpa データの永続性についていくつか質問したいと思います。ここに私の2つの主要な問題があります:
1)私は休止状態を使用して、一般的なユーザータイプとタプリザーを使用して列挙を永続化しています。これは私のサンプルコードです:
一般的な列挙永続型:
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;
}
}
さて、このクラスではすべてがうまく機能しています。私が必要とするのは、いくつかの改善を行うことです:
enum テーブルと DB テーブルにも言語があるため、次のようになります。
----> 言語[] 言語 = Language.values(); (言語は上記の列挙型の名前です)
データベースからエンティティを取得せずに、列挙から直接オブジェクトを使用したい: つまり、これを行いたい:
話し言葉を設定する = new HashSet(); speakLanguages.add(Language.ENGLISH); 申し込む
r.setSpokenLanguages(spokenLanguages);
これを行う代わりに:
話し言葉を設定する = new HashSet(); speakLanguages.add(languageService.getLanguageById(Language.ENGLISH.getCodeValue())); 申し込む
r.setSpokenLanguages(spokenLanguages);
dao の使用とデータベース アクセスをバイパスしたいのですが、要素が DB に挿入され、id が明らかに存在するため、毎回例外が発生します。
Id が自動生成されていなくても、DB から取得されていない場合、Hibernate は要素を挿入します。したがって、このケースを処理する方法があるかどうか、または起動時にアプリケーション全体を初期化し、列挙型からではなく DB から言語リストをロードするクラスのように想像できる解決策があるかどうか疑問に思います。
2 )
JPA 2.0 マッピングを使用しています。hibernate-jpa-2.0 と hibernate 4.1.0.final を使用
2 つのクラスの間に @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}"
どんな助けでも大歓迎です。ありがとう