Автор оригинала: Vlad Mihalcea.
В этой статье вы узнаете, как сопоставить свойства сущности camelcase (например, номер телефона ) с именами столбцов snake_case (например, номер телефона ), используя стратегию именования в режиме гибернации.
Хотя вы могли бы достичь той же цели с помощью атрибута name аннотации JPA @Column , гораздо удобнее использовать пользовательскую стратегию гибернации для последовательного применения этого соглашения об именовании.
Давайте предположим, что мы используем следующие Автор книги и Книга в мягкой обложке сущности в нашем приложении:
Объекты JPA отображаются следующим образом:
@Entity(name = "BookAuthor")
public class BookAuthor {
@Id
private Long id;
private String firstName;
private String lastName;
//Getters and setters omitted for brevity
}
@Entity(name = "PaperBackBook")
public class PaperBackBook {
@Id
@GeneratedValue(
strategy = GenerationType.SEQUENCE
)
private Long id;
@NaturalId
private String ISBN;
private String title;
private LocalDate publishedOn;
@ManyToOne(fetch = FetchType.LAZY)
private BookAuthor publishedBy;
//Getters and setters omitted for brevity
}
Ассоциация @ManyToOne использует ленивую загрузку, потому что стратегия быстрой выборки по умолчанию почти всегда является плохой идеей .
Схема базы данных, связанная с сопоставлением JPA по умолчанию
Если мы создадим схему базы данных с помощью инструмента hbm2ddl , будут выполнены следующие инструкции DDL:
CREATE SEQUENCE hibernate_sequence
START WITH 1 INCREMENT BY 1
CREATE TABLE BookAuthor (
id BIGINT NOT NULL,
firstName VARCHAR(255),
lastName VARCHAR(255),
PRIMARY KEY (id)
)
CREATE TABLE PaperBackBook (
id BIGINT NOT NULL,
ISBN VARCHAR(255),
publishedOn DATE,
title VARCHAR(255),
publishedBy_id BIGINT,
PRIMARY KEY (id)
)
По умолчанию Hibernate принимает имя класса сущностей, а также имена свойств при сопоставлении сущностей JPA с базовыми таблицами базы данных. Однако, хотя соглашение об именовании camelcase подходит для кода Java, мы хотим использовать соглашение об именовании snake_case для схемы базы данных. К счастью, Hibernate очень расширяем, поэтому мы можем достичь этой цели, используя собственную стратегию именования.
Начиная с Hibernate 5, стратегия именования объектов базы данных представлена интерфейсом PhysicalNamingStrategy , который мы можем настроить для автоматического преобразования идентификаторов базы данных из cameCase в snake_case.
public class CamelCaseToSnakeCaseNamingStrategy
extends PhysicalNamingStrategyStandardImpl {
public static final CamelCaseToSnakeCaseNamingStrategy INSTANCE =
new CamelCaseToSnakeCaseNamingStrategy();
public static final String CAMEL_CASE_REGEX = "([a-z]+)([A-Z]+)";
public static final String SNAKE_CASE_PATTERN = "$1\\_$2";
@Override
public Identifier toPhysicalCatalogName(
Identifier name,
JdbcEnvironment context) {
return formatIdentifier(
super.toPhysicalCatalogName(name, context)
);
}
@Override
public Identifier toPhysicalSchemaName(
Identifier name,
JdbcEnvironment context) {
return formatIdentifier(
super.toPhysicalSchemaName(name, context)
);
}
@Override
public Identifier toPhysicalTableName(
Identifier name,
JdbcEnvironment context) {
return formatIdentifier(
super.toPhysicalTableName(name, context)
);
}
@Override
public Identifier toPhysicalSequenceName(
Identifier name,
JdbcEnvironment context) {
return formatIdentifier(
super.toPhysicalSequenceName(name, context)
);
}
@Override
public Identifier toPhysicalColumnName(
Identifier name,
JdbcEnvironment context) {
return formatIdentifier(
super.toPhysicalColumnName(name, context)
);
}
private Identifier formatIdentifier(
Identifier identifier) {
if (identifier != null) {
String name = identifier.getText();
String formattedName = name
.replaceAll(
CAMEL_CASE_REGEX,
SNAKE_CASE_PATTERN)
.toLowerCase();
return !formattedName.equals(name) ?
Identifier.toIdentifier(
formattedName,
identifier.isQuoted()
) :
identifier;
} else {
return null;
}
}
}
Вам даже не нужно создавать вышеупомянутый класс стратегии именования. Вы можете получить его с помощью зависимости hibernate-types Maven:
com.vladmihalcea hibernate-types-55 ${hibernate-types.version}
Чтобы использовать camelCase Для стратегии именования случаев змеи пользовательской стратегии именования, вам необходимо предоставить ее в режим гибернации через свойство hibernate.physical_naming_strategy конфигурация:
Теперь при создании схемы базы данных с использованием hbm2ll Hibernate выполнит следующие инструкции DDL:
CREATE SEQUENCE hibernate_sequence
START WITH 1 INCREMENT BY 1
CREATE TABLE book_author (
id BIGINT NOT NULL,
first_name VARCHAR(255),
last_name VARCHAR(255),
PRIMARY KEY (id)
)
CREATE TABLE paper_back_book (
id BIGINT NOT NULL,
isbn VARCHAR(255),
published_on DATE,
title VARCHAR(255),
published_by_id BIGINT,
PRIMARY KEY (id)
)
Намного лучше, правда?
Хотя широко известно, что вы можете настроить сопоставление идентификаторов JPA с БД с помощью атрибута name аннотации JPA @Column , гораздо удобнее использовать стратегию гибернации для автоматического применения данного соглашения об именовании к десяткам или сотням объектов.
И вам даже не нужно самостоятельно писать стратегию именования, так как вы можете получить ее с помощью проекта hibernate-types с открытым исходным кодом, который даже поддерживает старый контракт NamingStrategy Hibernate 4.