あなたはHibernateクラスをマップするのを手伝ってもらえますか?Hibernateを使用したマッピング配列
public class MyClass{
private Long id;
private String name;
private int[] values;
...
}
私は、PostgreSQLと列タイプを使用しているn個の表は、整数私の配列をマッピングする必要がありますどのように[] のですか?
あなたはHibernateクラスをマップするのを手伝ってもらえますか?Hibernateを使用したマッピング配列
public class MyClass{
private Long id;
private String name;
private int[] values;
...
}
私は、PostgreSQLと列タイプを使用しているn個の表は、整数私の配列をマッピングする必要がありますどのように[] のですか?
私は決して休止状態に配列をマップしていません。私はいつもコレクションを使用しています。だから、私は少しクラスを変更しました:
public class MyClass{
private Long id;
private String name;
private List<Integer> values;
@Id
// this is only if your id is really auto generated
@GeneratedValue(strategy=GenerationType.AUTO)
public Long getId() {
return id;
}
@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY)
public List<Integer> getValues() {
return values;
}
...
Hibernate(とJPA)はPostgreSQLの配列タイプを直接マッピングすることはできません。 See this questionあなたが実際にデータベース構造をそのまま保持する必要がある場合は、どのように処理を進めますか。 This threadには、必要なカスタムタイプの例があります。
スキーマを変更できる場合は、コレクションを処理するために追加のテーブルを作成することができます(List<Integer>
)。次に、使用している冬眠のバージョンによって:
@ElementCollection
@CollectionOfElements
を使用しています。 hibernate jarパッケージのorg.hibernate.typeフォルダを確認してください。 int配列はそれらの1つではありません。したがって、UserTypeインターフェイスを実装できるカスタムタイプを記述する必要があります。
public class MyClass{
private Long id;
private String name;
private Integer[] values;
@Type(type = "com.usertype.IntArrayUserType")
public Integer[] getValues(){
return values;
}
public void setValues(Integer[] values){
this.values = values;
}
}
IntArrayUserType.class
package com.usertype.IntArrayUserType;
public class IntArrayUserType implements UserType {
protected static final int[] SQL_TYPES = { Types.ARRAY };
@Override
public Object assemble(Serializable cached, Object owner) throws HibernateException {
return this.deepCopy(cached);
}
@Override
public Object deepCopy(Object value) throws HibernateException {
return value;
}
@Override
public Serializable disassemble(Object value) throws HibernateException {
return (Integer[]) this.deepCopy(value);
}
@Override
public boolean equals(Object x, Object y) throws HibernateException {
if (x == null) {
return y == null;
}
return x.equals(y);
}
@Override
public int hashCode(Object x) throws HibernateException {
return x.hashCode();
}
@Override
public boolean isMutable() {
return true;
}
@Override
public Object nullSafeGet(ResultSet resultSet, String[] names, SessionImplementor session, Object owner)
throws HibernateException, SQLException {
if (resultSet.wasNull()) {
return null;
}
if(resultSet.getArray(names[0]) == null){
return new Integer[0];
}
Array array = resultSet.getArray(names[0]);
Integer[] javaArray = (Integer[]) array.getArray();
return javaArray;
}
@Override
public void nullSafeSet(PreparedStatement statement, Object value, int index, SessionImplementor session)
throws HibernateException, SQLException {
Connection connection = statement.getConnection();
if (value == null) {
statement.setNull(index, SQL_TYPES[0]);
} else {
Integer[] castObject = (Integer[]) value;
Array array = connection.createArrayOf("integer", castObject);
statement.setArray(index, array);
}
}
@Override
public Object replace(Object original, Object target, Object owner) throws HibernateException {
return original;
}
@Override
public Class<Integer[]> returnedClass() {
return Integer[].class;
}
@Override
public int[] sqlTypes() {
return new int[] { Types.ARRAY };
}
あなたはMyClassのエンティティを照会するときは、このような何かを追加することができます:私はthis articleで説明したように持つ配列をマッピングし、
Type intArrayType = new TypeLocatorImpl(new TypeResolver()).custom(IntArrayUserType.class);
Query query = getSession().createSQLQuery("select values from MyClass")
.addScalar("values", intArrayType);
List<Integer[]> results = (List<Integer[]>) query.list();
これを運用環境で使用していますか?これはあなたのために働きますか? – corsiKa
はい、本番環境で作業しています。このコードを自分の作業コードからコピーしました – user3820369
をHibernateにはカスタムタイプが必要です。
public class ArraySqlTypeDescriptor
implements SqlTypeDescriptor {
public static final ArraySqlTypeDescriptor INSTANCE =
new ArraySqlTypeDescriptor();
@Override
public int getSqlType() {
return Types.ARRAY;
}
@Override
public boolean canBeRemapped() {
return true;
}
@Override
public <X> ValueBinder<X> getBinder(
JavaTypeDescriptor<X> javaTypeDescriptor) {
return new BasicBinder<X>(javaTypeDescriptor, this) {
@Override
protected void doBind(
PreparedStatement st,
X value,
int index,
WrapperOptions options
) throws SQLException {
AbstractArrayTypeDescriptor<Object> abstractArrayTypeDescriptor =
(AbstractArrayTypeDescriptor<Object>)
javaTypeDescriptor;
st.setArray(
index,
st.getConnection().createArrayOf(
abstractArrayTypeDescriptor.getSqlArrayType(),
abstractArrayTypeDescriptor.unwrap(
value,
Object[].class,
options
)
)
);
}
@Override
protected void doBind(
CallableStatement st,
X value,
String name,
WrapperOptions options
) throws SQLException {
throw new UnsupportedOperationException(
"Binding by name is not supported!"
);
}
};
}
@Override
public <X> ValueExtractor<X> getExtractor(
final JavaTypeDescriptor<X> javaTypeDescriptor) {
return new BasicExtractor<X>(javaTypeDescriptor, this) {
@Override
protected X doExtract(
ResultSet rs,
String name,
WrapperOptions options
) throws SQLException {
return javaTypeDescriptor.wrap(
rs.getArray(name),
options
);
}
@Override
protected X doExtract(
CallableStatement statement,
int index,
WrapperOptions options
) throws SQLException {
return javaTypeDescriptor.wrap(
statement.getArray(index),
options
);
}
@Override
protected X doExtract(
CallableStatement statement,
String name,
WrapperOptions options
) throws SQLException {
return javaTypeDescriptor.wrap(
statement.getArray(name),
options
);
}
};
}
}
そしてIntArrayTypeDescriptor
:
public class IntArrayTypeDescriptor
extends AbstractArrayTypeDescriptor<int[]> {
public static final IntArrayTypeDescriptor INSTANCE =
new IntArrayTypeDescriptor();
public IntArrayTypeDescriptor() {
super(int[].class);
}
@Override
protected String getSqlArrayType() {
return "integer";
}
}
JavaベースのバルクあなたがもArraySqlTypeDescriptor
必要
public class IntArrayType
extends AbstractSingleColumnStandardBasicType<int[]>
implements DynamicParameterizedType {
public IntArrayType() {
super(
ArraySqlTypeDescriptor.INSTANCE,
IntArrayTypeDescriptor.INSTANCE
);
}
public String getName() {
return "int-array";
}
@Override
protected boolean registerUnderJavaType() {
return true;
}
@Override
public void setParameterValues(Properties parameters) {
((IntArrayTypeDescriptor)
getJavaTypeDescriptor())
.setParameterValues(parameters);
}
}
:
だから、あなたはこのようなIntArrayType
を定義すると仮定するとto-JDBC型の処理は、に含まれています回のベースクラス:
public abstract class AbstractArrayTypeDescriptor<T>
extends AbstractTypeDescriptor<T>
implements DynamicParameterizedType {
private Class<T> arrayObjectClass;
@Override
public void setParameterValues(Properties parameters) {
arrayObjectClass = ((ParameterType) parameters
.get(PARAMETER_TYPE))
.getReturnedClass();
}
public AbstractArrayTypeDescriptor(Class<T> arrayObjectClass) {
super(
arrayObjectClass,
(MutabilityPlan<T>) new MutableMutabilityPlan<Object>() {
@Override
protected T deepCopyNotNull(Object value) {
return ArrayUtil.deepCopy(value);
}
}
);
this.arrayObjectClass = arrayObjectClass;
}
@Override
public boolean areEqual(Object one, Object another) {
if (one == another) {
return true;
}
if (one == null || another == null) {
return false;
}
return ArrayUtil.isEquals(one, another);
}
@Override
public String toString(Object value) {
return Arrays.deepToString((Object[]) value);
}
@Override
public T fromString(String string) {
return ArrayUtil.fromString(
string,
arrayObjectClass
);
}
@SuppressWarnings({ "unchecked" })
@Override
public <X> X unwrap(
T value,
Class<X> type,
WrapperOptions options
) {
return (X) ArrayUtil.wrapArray(value);
}
@Override
public <X> T wrap(
X value,
WrapperOptions options
) {
if(value instanceof Array) {
Array array = (Array) value;
try {
return ArrayUtil.unwrapArray(
(Object[]) array.getArray(),
arrayObjectClass
);
}
catch (SQLException e) {
throw new IllegalArgumentException(e);
}
}
return (T) value;
}
protected abstract String getSqlArrayType();
}
AbstractArrayTypeDescriptor
は、Java配列の深いコピー、ラッピングやアンラップロジックを処理するためにArrayUtilに依存しています。
さて、あなたはマッピングは次のようになりますよ:それは動作しません
@Entity(name = "Event")
@Table(name = "event")
@TypeDef(
name = "int-array",
typeClass = IntArrayType.class
)
public static class Event
extends BaseEntity {
@Type(type = "int-array")
@Column(
name = "sensor_values",
columnDefinition = "integer[]"
)
private int[] sensorValues;
//Getters and setters omitted for brevity
}
。 '原因:org.hibernate。AnnotationException:マップされていないクラスを対象とした@OneToManyまたは@ManyToManyの使用 ' –