Рубрики
Без рубрики

Как сопоставить свойства camelCase с именами столбцов snake_case с помощью Hibernate

Узнайте, как сопоставить свойства сущности Camelcase, такие как номер телефона, с именами столбцов, такими как номер телефона, с помощью стратегии именования в режиме гибернации.

Автор оригинала: 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.