postgresql 使用HibernateMap数组

oknwwptz  于 2023-10-18  发布在  PostgreSQL
关注(0)|答案(5)|浏览(130)

你能帮我用HibernateMap这个类吗?

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

我正在使用PostgreSQL,表中的列类型是integer[]我的数组应该如何Map?

8ulbf1ek

8ulbf1ek1#

Hibernate(和JPA)不能直接MapPostgreSQL数组类型。See this question了解如果您确实需要保持数据库结构不变,如何继续。This thread有一个所需自定义类型的示例。
如果你可以改变你的模式,你可以让hibernate创建一个额外的表来处理集合List<Integer>。然后,根据您使用的Hibernate版本:

ikfrs5lh

ikfrs5lh2#

Hibernate只能Map基本类型。在hibernatejar包的org. hibernate.type文件夹下检查。int数组不是其中之一。因此,您必须编写一个可以实现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();
rbpvctlc

rbpvctlc3#

Maven依赖

你需要做的第一件事是在项目pom.xml配置文件中设置以下Hypersistence Utils Maven依赖项:

<dependency>
    <groupId>io.hypersistence</groupId>
    <artifactId>hypersistence-utils-hibernate-62</artifactId>
    <version>${hypersistence-utils.version}</version>
</dependency>

Maven ARRAY列

假设你的数据库中有这个表:

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

你想把它Map成这样:

@Entity(name = "Event")
@Table(name = "event")
public class Event {

    @Id
    private Long id;
 
    @Type(StringArrayType.class)
    @Column(
        name = "sensor_names", 
        columnDefinition = "text[]"
    )
    private String[] sensorNames;
 
    @Type(IntArrayType.class)
    @Column(
        name = "sensor_values", 
        columnDefinition = "integer[]"
    )
    private int[] sensorValues;
 
    //Getters and setters omitted for brevity
}

StringArrayTypeIntArrayType是Hypersistence Utils项目提供的类。

测试时间

现在,当你插入几个实体时:

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
)
nwsw7zdq

nwsw7zdq4#

我从来没有把数组Map到休眠状态。我总是使用集合。所以,我稍微改变了你的类:

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

pjngdqdw5#

从Hibernate 6.1 Final开始,如果可能的话,基本数组和集合现在可以Map到数据库ARRAY类型,或者JSON/XML类型。
https://in.relation.to/2022/06/14/orm-61-final/

相关问题