Статьи

Как сопоставить перечисления PostgreSQL со свойствами сущностей JPA с помощью Hibernate

Вступление

Проект hibernate-types открытым исходным кодом позволяет отображать JSON, ARRAY, YearMonth , Month или столбцы, специфичные для базы данных (например, адреса INET).

В этой статье мы рассмотрим, как можно сопоставить тип Enum PostgreSQL с массивом Java при использовании JPA и Hibernate.

Maven зависимость

Прежде всего, вам нужно настроить следующую зависимость Maven в pom.xml конфигурации вашего проекта pom.xml :

1
2
3
4
5
<dependency>
    <groupId>com.vladmihalcea</groupId>
    <artifactId>hibernate-types-52</artifactId>
    <version>2.3.5</version>
</dependency>

Если вы используете более старые версии Hibernate, обратитесь к репозиторию GitHub hibernate-types для получения дополнительной информации о зависимости соответствия для текущей версии Hibernate.

Модель предметной области

Давайте предположим, что в нашей схеме базы данных есть следующее перечисление sensor_state PostgreSQL:

1
2
3
4
5
CREATE TYPE sensor_state AS ENUM (
    'ONLINE',
    'OFFLINE',
    'UNKNOWN'
);

Наше приложение должно хранить События в следующей таблице базы данных:

1
2
3
4
5
6
7
CREATE TABLE event (
  id bigint NOT NULL,
  sensor_names text[],
  sensor_values integer[],
  sensor_states sensor_state[],
  CONSTRAINT event_pkey PRIMARY KEY (id)
)

Обратите внимание, что sensor_names , sensor_values и sensor_states хранятся в виде массивов. Чтобы сопоставить типы столбцов массива PostgreSQL с массивами Java, вам нужен собственный тип Hibernate, поскольку встроенные типы не поддерживают сохранение специфичных для базы данных массивов.

Однако благодаря библиотеке hibernate-types вы можете легко сопоставить таблицу event со следующей сущностью Event :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
@Entity(name = "Event")
@Table(name = "event")
@TypeDefs({
    @TypeDef(
        typeClass = StringArrayType.class,
        defaultForType = String[].class
    ),
    @TypeDef(
        typeClass = IntArrayType.class,
        defaultForType = int[].class
    ),
    @TypeDef(
        typeClass = EnumArrayType.class,
        defaultForType = SensorState[].class,
        parameters = {
            @Parameter(
                name = EnumArrayType.SQL_ARRAY_TYPE,
                value = "sensor_state"
            )
        }
    )
})
public class Event {
 
    @Id
    private Long id;
 
    @Column(
        name = "sensor_names",
        columnDefinition = "text[]"
    )
    private String[] sensorNames;
 
    @Column(
        name = "sensor_values",
        columnDefinition = "integer[]"
    )
    private int[] sensorValues;
 
    @Column(
        name = "sensor_states",
        columnDefinition = "sensor_state[]"
    )
    private SensorState[] sensorStates;
 
    public Long getId() {
        return id;
    }
 
    public Event setId(
            Long id) {
        this.id = id;
        return this;
    }
 
    public String[] getSensorNames() {
        return sensorNames;
    }
 
    public Event setSensorNames(
            String[] sensorNames) {
        this.sensorNames = sensorNames;
        return this;
    }
 
    public int[] getSensorValues() {
        return sensorValues;
    }
 
    public Event setSensorValues(
            int[] sensorValues) {
        this.sensorValues = sensorValues;
        return this;
    }
 
    public SensorState[] getSensorStates() {
        return sensorStates;
    }
 
    public Event setSensorStates(
            SensorState[] sensorStates) {
        this.sensorStates = sensorStates;
        return this;
    }
}

Обратите внимание на API в стиле Fluent, используемый сущностью Event . В то время как JPA является более строгим, когда дело доходит до определения сеттеров, Hibernate позволяет вам определять сеттеры, чтобы вы могли строить сущность, используя API в стиле Fluent. Для более подробной информации, проверьте эту статью .

Аннотация @TypeDef используется для определения соответствия между типами классов массива Java и связанными с ними типами Hibernate:

  • Тип массива Java String[] обрабатывается StringArrayType .
  • Тип массива Java int[] обрабатывается IntArrayType
  • Java SensorState[] обрабатывается EnumArrayType . Параметр EnumArrayType.SQL_ARRAY_TYPE используется для описания специфичного для базы данных типа столбца, используемого для хранения Enum.

SensorState Java SensorState отображается следующим образом:

1
2
3
4
5
public enum SensorState {
    ONLINE,
    OFFLINE,
    UNKNOWN;
}

Время тестирования

Теперь при сохранении следующего объекта Event :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
entityManager.persist(
    new Event()
    .setId(1L)
    .setSensorNames(
        new String[]{
            "Temperature",
            "Pressure"
        })
    .setSensorValues(
        new int[]{
            12,
            756
        }
    )
    .setSensorStates(
        new SensorState[]{
            SensorState.ONLINE,
            SensorState.OFFLINE,
            SensorState.ONLINE,    
            SensorState.UNKNOWN
        }
    )  
);

Hibernate выполняет следующую инструкцию SQL INSERT:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
Query:["
    insert into event (
        sensor_names,
        sensor_states,
        sensor_values,
        id
    )
    values (
        ?,
        ?,
        ?,
        ?
    )
"],
Params:[(
    {"Temperature","Pressure"},
    {"ONLINE","OFFLINE","ONLINE","UNKNOWN"},
    {"12","756"},
    1
)]

И когда мы выбираем сущность Event , мы видим, что все свойства выбраны правильно

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Event event = entityManager.find(Event.class, 1L);
 
assertArrayEquals(
    new String[]{
        "Temperature",
        "Pressure"
    },
    event.getSensorNames()
);
 
assertArrayEquals(
    new int[]{
        12,
        756
    },
    event.getSensorValues()
);
 
assertArrayEquals(
    new SensorState[]{
        SensorState.ONLINE,
        SensorState.OFFLINE,
        SensorState.ONLINE,
        SensorState.UNKNOWN
    },
    event.getSensorStates()
);

Круто, верно?

Если вам понравилась эта статья, держу пари, что вам понравятся и мои книжные и видео курсы .

карта PostgreSQL Enums

карта PostgreSQL Enums

Вывод

Проект hibernate-types поддерживает больше, чем типы ARRAY. Вы можете отобразить специфичные для PostgreSQL Enums, Nullable Character , JSON или даже предоставить свои собственные неизменяемые пользовательские Types Hibernate.

Чтобы узнать больше о проекте hibernate-types , ознакомьтесь с этой статьей .

Опубликовано на Java Code Geeks с разрешения Влада Михалча, партнера нашей программы JCG. См. Оригинальную статью здесь: Как отобразить PostgreSQL Enums на свойства сущностей JPA с помощью Hibernate

Мнения, высказанные участниками Java Code Geeks, являются их собственными.