1. Обзор
PostgreSQL поддерживает определение массивов любого типа (встроенных или определяемых пользователем) как типов столбцов таблицы . В этом руководстве мы рассмотрим несколько способов сопоставления массива PostgreSQL с помощью Hibernate .
2. Базовая установка
В качестве предварительного условия для подключения к базе данных PostgreSQL мы должны добавить последнюю зависимость postgresql
Maven в наш pom.xml
вместе с конфигурациями Hibernate. Кроме того, давайте создадим класс сущности с именем User
с ролями
массива String
: ``
@Entity
public class User {
@Id
private Long id;
private String name;
private String[] roles;
//getters and setters
}
3. Пользовательские типы гибернации
Hibernate поддерживает пользовательские типы для сопоставления пользовательского типа с запросами SQL. Поэтому мы можем создавать собственные типы для сопоставления массива PostgreSQL с Hibernate для хранения/выборки данных. Во-первых, давайте создадим класс CustomStringArrayType
, реализующий класс UserType
Hibernate, `` чтобы предоставить пользовательский тип для сопоставления массива String :
public class CustomStringArrayType implements UserType {
@Override
public int[] sqlTypes() {
return new int[]{Types.ARRAY};
}
@Override
public Class returnedClass() {
return String[].class;
}
@Override
public Object nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner)
throws HibernateException, SQLException {
Array array = rs.getArray(names[0]);
return array != null ? array.getArray() : null;
}
@Override
public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor session)
throws HibernateException, SQLException {
if (value != null && st != null) {
Array array = session.connection().createArrayOf("text", (String[])value);
st.setArray(index, array);
} else {
st.setNull(index, sqlTypes()[0]);
}
}
//implement equals, hashCode, and other methods
}
Здесь следует отметить, что возвращаемый
тип метода returnClass — это массив String
. Также метод nullSafeSet
создает массив PostgreSQL типа text
.
4. Сопоставление массива с пользовательскими типами гибернации
4.1. Пользовательская
сущность
Затем мы будем использовать класс CustomStringArrayType
для сопоставления ролей
массива String с
текстовым
массивом PostgreSQL :
@Entity
public class User {
//...
@Column(columnDefinition = "text[]")
@Type(type = "com.foreach.hibernate.arraymapping.CustomStringArrayType")
private String[] roles;
//getters and setters
}
Вот и все! Мы готовы с нашей собственной реализацией типа и сопоставлением массива для выполнения операций CRUD над сущностью пользователя .
4.2. Модульный тест
Чтобы протестировать наш пользовательский тип, давайте сначала вставим объект User
вместе с ролями
массива String
: ``
@Test
public void givenArrayMapping_whenArraysAreInserted_thenPersistInDB()
throws HibernateException, IOException {
transaction = session.beginTransaction();
User user = new User();
user.setId(2L);
user.setName("smith");
String[] roles = {"admin", "employee"};
user.setRoles(roles);
session.persist(user);
session.flush();
session.clear();
transaction.commit();
User userDBObj = session.find(User.class, 2L);
assertEquals("smith", userDBObj.getName());
}
Также мы можем получить запись пользователя
, содержащую роли , в виде
текстового
массива PostgreSQL :
@Test
public void givenArrayMapping_whenQueried_thenReturnArraysFromDB()
throws HibernateException, IOException {
User user = session.find(User.class, 2L);
assertEquals("smith", user.getName());
assertEquals("admin", user.getRoles()[0]);
assertEquals("employee", user.getRoles()[1]);
}
4.3. CustomIntegerArrayType
Точно так же мы можем создать собственный тип для различных типов массивов, поддерживаемых PostgreSQL. Например, давайте создадим CustomIntegerArrayType для сопоставления массива
int
PostgreSQL :
public class CustomIntegerArrayType implements UserType {
@Override
public int[] sqlTypes() {
return new int[]{Types.ARRAY};
}
@Override
public Class returnedClass() {
return Integer[].class;
}
@Override
public Object nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner)
throws HibernateException, SQLException {
Array array = rs.getArray(names[0]);
return array != null ? array.getArray() : null;
}
@Override
public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor session)
throws HibernateException, SQLException {
if (value != null && st != null) {
Array array = session.connection().createArrayOf("int", (Integer[])value);
st.setArray(index, array);
} else {
st.setNull(index, sqlTypes()[0]);
}
}
//implement equals, hashCode, and other methods
}
Подобно тому, что мы заметили в классе CustomStringArrayType
, возвращаемый
тип метода returnClass — массив Integer
. Также реализация метода nullSafeSet
создает массив PostgreSQL типа int
. Наконец, мы можем использовать класс CustomIntegerArrayType
для сопоставления местоположений
массива Integer с массивом
int
PostgreSQL :
@Entity
public class User {
//...
@Column(columnDefinition = "int[]")
@Type(type = "com.foreach.hibernate.arraymapping.CustomIntegerArrayType")
private Integer[] locations;
//getters and setters
}
5. Сопоставление массива с спящими типами
С другой стороны, вместо реализации собственного типа для каждого типа, такого как String
, Integer
и Long
, мы можем использовать библиотеку типов hibernate,
разработанную известным экспертом по Hibernate Владом Михалча.
5.1. Настраивать
Во- первых, мы добавим последнюю зависимость Maven hibernate-types-52
в наш pom.xml
:
<dependency>
<groupId>com.vladmihalcea</groupId>
<artifactId>hibernate-types-52</artifactId>
<version>2.10.4</version>
</dependency>
5.2. Пользовательская
сущность
Далее мы добавим код интеграции в сущность User
для сопоставления массива String
phoneNumbers
:
@TypeDefs({
@TypeDef(
name = "string-array",
typeClass = StringArrayType.class
)
})
@Entity
public class User {
//...
@Type(type = "string-array")
@Column(
name = "phone_numbers",
columnDefinition = "text[]"
)
private String[] phoneNumbers;
//getters and setters
}
Здесь, подобно пользовательскому типу CustomStringArrayType
, мы использовали класс StringArrayType
, предоставленный библиотекой hibernate-types
, в качестве преобразователя для массива String .
Точно так же мы можем найти в библиотеке несколько других удобных преобразователей, таких как DateArrayType
, EnumArrayType
и DoubleArrayType
.
5.3. Модульный тест
Вот и все! Мы готовы к отображению массива с помощью библиотеки hibernate-types .
Обновим уже обсуждавшийся модульный тест, чтобы проверить операцию вставки:
@Test
public void givenArrayMapping_whenArraysAreInserted_thenPersistInDB()
throws HibernateException, IOException {
transaction = session.beginTransaction();
User user = new User();
user.setId(2L);
user.setName("smith");
String[] roles = {"admin", "employee"};
user.setRoles(roles);
String[] phoneNumbers = {"7000000000", "8000000000"};
user.setPhoneNumbers(phoneNumbers);
session.persist(user);
session.flush();
session.clear();
transaction.commit();
}
Точно так же мы можем проверить операцию чтения:
@Test
public void givenArrayMapping_whenQueried_thenReturnArraysFromDB()
throws HibernateException, IOException {
User user = session.find(User.class, 2L);
assertEquals("smith", user.getName());
assertEquals("admin", user.getRoles()[0]);
assertEquals("employee", user.getRoles()[1]);
assertEquals("7000000000", user.getPhoneNumbers()[0]);
assertEquals("8000000000", user.getPhoneNumbers()[1]);
}
6. Заключение
В этой статье мы рассмотрели сопоставление массива PostgreSQL с Hibernate. Во-первых, мы создали собственный тип для отображения массива String
с помощью класса UserType Hibernate.
Затем мы использовали пользовательский тип для сопоставления текстового
массива PostgreSQL с Hibernate. Наконец, мы использовали библиотеку hibernate-types
для сопоставления массива PostgreSQL. Как обычно, исходный код доступен на GitHub .