Автор оригинала: Vlad Mihalcea.
Вступление
В этой статье мы рассмотрим, как сопоставить тип столбца интервала PostgreSQL с объектом длительности Java с помощью Hibernate и hibernate-типов
проекта.
Еще одна очень полезная функция, представленная проектом hibernate-types
, заключается в том, что все типы, расширяющие Неизменяемый тип
, теперь могут рассматриваться как стандартные org.hibernate.type.Введите
, что позволит значительно улучшить интеграцию API ядра Hibernate.
Модель предметной области
Предполагая, что у нас есть следующая таблица книга
базы данных, которая определяет столбец presale_period
типа интервал|/.
Мы можем сопоставить таблицу book
с сущностью Book
JPA следующим образом:
@Entity(name = "Book") @Table(name = "book") @TypeDef( typeClass = PostgreSQLIntervalType.class, defaultForType = Duration.class ) @TypeDef( typeClass = YearMonthDateType.class, defaultForType = YearMonth.class ) public class Book { @Id @GeneratedValue private Long id; @NaturalId private String isbn; private String title; @Column( name = "published_on", columnDefinition = "date" ) private YearMonth publishedOn; @Column( name = "presale_period", columnDefinition = "interval" ) private Duration presalePeriod; public Long getId() { return id; } public Book setId(Long id) { this.id = id; return this; } public String getIsbn() { return isbn; } public Book setIsbn(String isbn) { this.isbn = isbn; return this; } public String getTitle() { return title; } public Book setTitle(String title) { this.title = title; return this; } public YearMonth getPublishedOn() { return publishedOn; } public Book setPublishedOn(YearMonth publishedOn) { this.publishedOn = publishedOn; return this; } public Duration getPresalePeriod() { return presalePeriod; } public Book setPresalePeriod(Duration presalePeriod) { this.presalePeriod = presalePeriod; return this; } }
Первое, что следует заметить, – это то, что методы настройки свойств сущности следуют шаблону проектирования интерфейса Fluent .
Второе, что вы можете заметить, это то, что мы определяем бизнес-ключ @NaturalID, который позволяет нам извлекать сущность на основе естественного идентификатора, даже если мы не знаем значения первичного ключа связанной записи таблицы.
Третье, что вы заметите, это то, что мы определяем несколько @TypeDef
аннотаций. Оба предназначены для типов объектов, представленных Java 8.
Чтобы отобразить тип Java Год Месяц
, мы можем использовать Тип даты Год Месяц
, как описано в этой статье .
Чтобы сопоставить столбец интервала PostgreSQL с Java Длительность
, нам нужно использовать тип интервала PostgreSQL
, предлагаемый проектом hibernate-types
.
Сопоставление столбцов интервала Java с интервалом PostgreSQL
При сохранении Книги
сущности:
entityManager.persist( new Book() .setIsbn("978-9730228236") .setTitle("High-Performance Java Persistence") .setPublishedOn(YearMonth.of(2016, 10)) .setPresalePeriod( Duration.between( LocalDate .of(2015, Month.NOVEMBER, 2) .atStartOfDay(), LocalDate .of(2016, Month.AUGUST, 25) .atStartOfDay() ) ) );
Мы видим, что Hibernate генерирует соответствующую инструкцию SQL INSERT:
INSERT INTO book ( isbn, presale_period, published_on, title, id ) VALUES ( '978-9730228236', '0 years 0 mons 297 days 0 hours 0 mins 0.00 secs', '2016-10-01', 'High-Performance Java Persistence', 1 )
При извлечении сущности Book
мы видим, что атрибут Период до продажи
Java Продолжительность
правильно заполнен соответствующим значением столбца PostgreSQL интервал|/.
Book book = entityManager .unwrap(Session.class) .bySimpleNaturalId(Book.class) .load("978-9730228236"); assertEquals( Duration.between( LocalDate .of(2015, Month.NOVEMBER, 2) .atStartOfDay(), LocalDate .of(2016, Month.AUGUST, 25) .atStartOfDay() ), book.getPresalePeriod() );
Хотя сохранение и извлечение сущности Book
, а также выполнение любого запроса JPQL и API критериев довольно просто, обработка собственных наборов результатов SQL-запросов сложнее при работе с типами столбцов, которые изначально не поддерживаются Hibernate.
Если Hibernate обнаруживает типы столбцов JDBC, для которых у него нет зарегистрированного типа Hibernate, то возникает исключение Без сопоставления диалектов для типа JDBC
.
Как я объяснил в этой статье , вы можете решить эту проблему, указав правильный тип гибернации для обработки данного типа столбца JDBC.
В следующем примере собственного SQL-запроса вы можете видеть, что псевдоним столбца published_on
результирующего набора настроен на использование типа YearMonthDateType
, в то время как псевдоним столбца presale_period
обрабатывается типом PostgreSQLIntervalType
.
Tuple result = (Tuple) entityManager .createNativeQuery( "SELECT " + " b.published_on AS published_on, " + " b.presale_period AS presale_period " + "FROM " + " book b " + "WHERE " + " b.isbn = :isbn ", Tuple.class) .setParameter("isbn", "978-9730228236") .unwrap(NativeQuery.class) .addScalar( "published_on", YearMonthDateType.INSTANCE ) .addScalar( "presale_period", PostgreSQLIntervalType.INSTANCE ) .getSingleResult(); assertEquals( YearMonth.of(2016, 10), result.get("published_on") ); assertEquals( Duration.between( LocalDate.of(2015, Month.NOVEMBER, 2).atStartOfDay(), LocalDate.of(2016, Month.AUGUST, 25).atStartOfDay() ), result.get("presale_period") );
Метод addScalar
интерфейса Hibernate Собственный запрос
принимает org.hibernate.тип.Введите
Ссылку на объект, в то время как YearMonthDateType
и PostgreSQLIntervalType
реализуют интерфейс UserType|/.
До выпуска 2.6 типов гибернации
было невозможно использовать Неизменяемый тип
, который расширяет интерфейс UserType
, в вызовах методов addScalar
. Однако начиная с версии 2.6 класс ImmutableType
abstract реализует как Тип пользователя
, так и org.hibernate.type.Введите
, поэтому передача неизменяемого типа
(который является базовым классом как YearMonthDateType
, так и PostgreSQLIntervalType
) в метод addScalar
больше не является проблемой.
Вывод
Проект hibernate-types
расширился, чтобы вместить большое разнообразие типов гибернации, которые изначально не поддерживаются. Например, теперь вы можете использовать JSON, МАССИВ, HStore, Диапазон, Int, Месяц года, Символ, допускающий значение null, и типы перечислений, специфичные для PostgreSQL.
Хотя вы также можете реализовать все эти типы самостоятельно, гораздо удобнее определить типы гибернации
зависимости в вашем проекте pom.xml
Файл конфигурации Maven и сосредоточьтесь на бизнес-логике приложения вместо написания типов, специфичных для гибернации.