Автор оригинала: Vlad Mihalcea.
Вступление
Сопоставление сущностей с таблицами базы данных обычно является очень простым процессом. Однако, если ваши сопоставления довольно необычны, вы можете столкнуться с некоторыми редкими проблемами, подобными той, которую я нашел на форуме Hibernate .
В этой статье я собираюсь объяснить сопоставление объектов Java с типами столбцов JDBC и базы данных и то, как вы можете устранить проблему, описанную в вышеупомянутом вопросе Hibernate.
Проблема с отображением
Учитывая, что у нас есть следующая схема базы данных SQL Server:
CREATE TABLE event ( id NUMERIC(19,0) IDENTITY NOT NULL, PRIMARY KEY (id) )
Это сопоставление схемы довольно необычно, поскольку гораздо чаще для столбца ИДЕНТИФИКАТОРОВ используется тип ЦЕЛОЕ ЧИСЛО
или BIGINT
. Однако, если вы имеете дело с устаревшей схемой, вам придется иметь дело с ней на стороне Java.
И вы предоставляете следующее сопоставление сущностей:
@Entity(name = "Event") @Table(name = "event") public class Event { @Id @GeneratedValue( strategy = GenerationType.IDENTITY ) private Long id; }
Если вы разрешите Hibernate проверить сопоставление с помощью параметра проверить hbm2ddl:
Hibernate создаст следующее исключение во время начальной загрузки приложения:
Caused by: org.hibernate.tool.schema.spi.SchemaManagementException: Schema-validation: wrong column type encountered in column [id] in table [event]; found [numeric (Types#NUMERIC)], but expecting [bigint (Types#BIGINT)]
Логика отображения длинных типов в режиме гибернации
Чтобы понять, почему проверка схемы не удалась, вы должны понять, как основные типы обрабатываются Hibernate. Например, java.lang.Длинный
тип обрабатывается org.hibernate.type.LongType
, диаграмма классов которого выглядит следующим образом:
SqlTypeDescriptor
используется для сопоставления типа Java с типом JDBC. Цель этого класса-привязать значение к Подготовленной инструкции
при выполнении инструкций INSERT, UPDATE или DELETE и извлечь значение из набора результатов
после выполнения инструкции SELECT.
JavaTypeDescriptor
используется для обработки сопоставления одного типа Java (например, Long
) с другим (например, Число
или Строка
) и используется при преобразовании значения, считанного из SqlTypeDescriptor
, в ожидаемый тип Java (например, Long
в этом случае).
Тип Long
использует следующий SqlTypeDescriptor
и JavaTypeDescriptor
:
public LongType() { super( BigIntTypeDescriptor.INSTANCE, LongTypeDescriptor.INSTANCE ); }
bigintypedescriptor
представляет реализацию SqlTypeDescriptor
, поэтому он ожидает java.sql.Types.BIGINT
на стороне JDBC. Однако в нашем сопоставлении базы данных используется тип ЧИСЛОВОЙ
столбец, который обозначается java.sql.Types.ЧИСЛОВОЙ тип
JDBC, отсюда и сообщение об ошибке, которое мы получили во время проверки схемы.
Устранение проблемы
Решение действительно простое. Нам просто нужно переопределить тип JDBC по умолчанию Hibernate, используя явное объявление типа:
@Id @GeneratedValue( strategy = GenerationType.IDENTITY ) @Column( columnDefinition = "NUMERIC(19,0)" ) private Long id;
Теперь Hibernate знает, что следует ожидать ЧИСЛОВОЙ
столбец на стороне базы данных, а не BIGINT
один.
Вывод
Явные сопоставления, такие как @Таблица
или @Столбец
, полезны не только при создании схемы базы данных с помощью инструмента hbm2ddl. Для производственной системы управление схемой базы данных с помощью такого инструмента, как Flyway – это путь, по которому нужно идти.
Однако вам необходимо убедиться, что схема сопоставления сущностей JPA синхронизирована с схемой базы данных, и именно в этом заключается стратегия validate hbm2ddl. Хотя сопоставления по умолчанию подходят для большинства случаев использования, иногда требуется предоставить явное объявление типа, например ЧИСЛОВОЙ
тип столбца для столбца ИДЕНТИФИКАТОРОВ.