web-dev-qa-db-ja.com

Hibernateを使用したマッピング配列

Hibernateを使用してこのクラスをマップするのを手伝ってくれませんか?

public class MyClass{
    private Long id;
    private String name;
    private int[] values;
    ...
}

PostgreSQLを使用していて、テーブルの列タイプはinteger []です。配列をどのようにマッピングする必要がありますか?

9
danny.lesnik

配列を休止状態にマップしたことはありません。私はいつもコレクションを使います。だから、私はあなたのクラスを少し変更しました:

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;
    }   
    ...
5
AlexR

Hibernate(およびJPA)は、PostgreSQL配列型を直接マップすることはできません。 この質問を参照 データベース構造をそのまま保持する必要がある場合の進め方について。 このスレッド には、必要なカスタムタイプの例があります。

スキーマを変更できる場合は、hibernateにコレクションを処理するための追加のテーブルを作成させることができます-List<Integer>。次に、使用しているHibernateのバージョンに応じて:

15
Bozho

Hibernateは、プリミティブ型のみをマップできます。 hibernatejarパッケージの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エンティティをクエリすると、次のようなものを追加できます。

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();
5
user3820369

これは非常に良い質問なので、 Hibernate Typesプロジェクト を使用してこの目標を達成する方法を説明するために この記事 と書くことにしました。

Mavenの依存関係

最初に行う必要があるのは、次の設定です Hibernateタイプ プロジェクトでのMaven依存関係pom.xml構成ファイル:

<dependency>
    <groupId>com.vladmihalcea</groupId>
    <artifactId>hibernate-types-52</artifactId>
    <version>${hibernate-types.version}</version>
</dependency>

MavenARRAY列

データベースにこのテーブルがあると仮定します。

create table event (
    id int8 not null, 
    version int4, 
    sensor_names text[], 
    sensor_values integer[], 
    primary key (id)
)

そして、あなたはそれをこのようにマッピングしたいと思います:

@Entity(name = "Event")
@Table(name = "event")
@TypeDefs({
    @TypeDef(
        name = "string-array", 
        typeClass = StringArrayType.class
    ),
    @TypeDef(
        name = "int-array", 
        typeClass = IntArrayType.class
    )
})
public static class Event extends BaseEntity {

    @Type( type = "string-array" )
    @Column(
        name = "sensor_names", 
        columnDefinition = "text[]"
    )
    private String[] sensorNames;

    @Type( type = "int-array" )
    @Column(
        name = "sensor_values", 
        columnDefinition = "integer[]"
    )
    private int[] sensorValues;

    //Getters and setters omitted for brevity
}

string-arrayおよびint-arrayは、BaseEntityスーパークラスで定義できるカスタムタイプです。

@TypeDefs({
    @TypeDef(
        name = "string-array", 
        typeClass = StringArrayType.class
    ),
    @TypeDef(
        name = "int-array", 
        typeClass = IntArrayType.class
    )
})
@MappedSuperclass
public class BaseEntity {

    @Id
    private Long id;

    @Version
    private Integer version;

    //Getters and setters omitted for brevity
}

StringArrayTypeIntArrayTypeは、HibernateTypesプロジェクトによって提供されるクラスです。

テスト時間

ここで、いくつかのエンティティを挿入すると、

Event nullEvent = new Event();
nullEvent.setId(0L);
entityManager.persist(nullEvent);

Event event = new Event();
event.setId(1L);
event.setSensorNames(
    new String[] {
        "Temperature", 
        "Pressure"
    }
);
event.setSensorValues( 
    new int[] {
        12, 
        756
    } 
);
entityManager.persist(event);

Hibernateは次のSQLステートメントを生成します。

INSERT INTO event (
    version, 
    sensor_names, 
    sensor_values, 
    id
) 
VALUES (
    0, 
    NULL(ARRAY), 
    NULL(ARRAY), 
    0
)

INSERT INTO event (
    version, 
    sensor_names, 
    sensor_values, 
    id
) 
VALUES ( 
    0, 
    {"Temperature","Pressure"}, 
    {"12","756"}, 
    1
)
3
Vlad Mihalcea