Почему в Spring Boot и Hibernate не работает по умолчанию Naming strategy?

Открываю официальную документацию по Spring Boot и вижу, что Spring Boot по умолчанию использует стратегию именования SpringPhysicalNamingStrategy, которая принадлежит Hibernate и подразумевает правила:

  • все точки заменяются символами подчеркивания
  • регистр camelCase заменяется также подчеркиванием
  • по умолчанию все имена таблиц создаются в нижнем регистре. Например, объект TelephoneNumber отображается в таблицу phone_number.

Есть у меня сущность GiftCertificate. Почему при выполнении запроса через EntityManager мой Entity-класс c именем GiftCertificate переименовывается в giftcertificate, а не в gift_certificate, как ожидается?

На всякий случай привожу пример:

  • запрос в БД:
    @Override
    public Set<GiftCertificate> findAll() {
        return entityManager.createQuery(FIND_ALL_GIFT_CERTIFICATES_SQL, GiftCertificate.class)
                .getResultStream()
                .collect(Collectors.toSet());
    }

Результат - java.sql.SQLSyntaxErrorException: Table 'gift_certificates_system_db.giftcertificate' doesn't exist

  • сущность GiftCertificate:
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@Entity
@EntityListeners(GiftCertificateListener.class)
public class GiftCertificate implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private String name;

    @Column(nullable = false)
    private String description;

    @Column(nullable = false)
    private BigDecimal price;

    @Column(nullable = false)
    private Integer duration;

    @Column(nullable = false)
    private LocalDateTime createDate;

    @Column(nullable = false)
    private LocalDateTime lastUpdateDate;
}
  • Конфигурация:
@Configuration
@EnableTransactionManagement
public class EsmConfiguration implements WebMvcConfigurer {

    private final DataSource dataSource;

    @Autowired
    public EsmConfiguration(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
        entityManagerFactoryBean.setDataSource(dataSource);
        entityManagerFactoryBean.setPersistenceProviderClass(HibernatePersistenceProvider.class);
        entityManagerFactoryBean.setPackagesToScan(ENTITY_PACKAGES_TO_SCAN);

        return entityManagerFactoryBean;
    }

    @Bean
    public JpaTransactionManager jpaTransactionManager() {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
        return transactionManager;
    }

    @Bean
    public MessageSource messageSource() {
        ResourceBundleMessageSource messages = new ResourceBundleMessageSource();
        messages.setBasename("locale");
        messages.setDefaultLocale(Locale.ENGLISH);
        messages.setDefaultEncoding("UTF-8");
        return messages;
    }

    @Bean
    public MethodValidationPostProcessor methodValidationPostProcessor() {
        return new MethodValidationPostProcessor();
    }
}

Что я пробовал:

  • в application.properties указывал явно spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl, но не помогает.
  • явно указывать @Table(name = "gift_certificate") - помогает, но меня интересует реализация по умолчанию без явного указания имен таблиц в куче сущностей, что загромождает код.

Ответы (1 шт):

Автор решения: Taylor

ImplicitNamingStrategy используется, когда явно не указывается имя базы данных, имя таблицы, имя столбца в определении сущности. Т.е. когда не используется аннотация @Table или если есть аннотация @Column, но свойство name не задано.

PhysicalNamingStrategy стратегия вступает в работу, когда явно задано имя БД, имя таблицы, имя столбца, например @Column(name = "camelCase"). Вот тогда Hibernate уже будет работать со значением параметра name.

Задаются свойства в application.properties:

spring.jpa.hibernate.naming.implicit-strategy=org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy
spring.jpa.hibernate.naming.physical-strategy=org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy

Мне нужно была стратегия ImplicitNamingStrategy, а не PhysicalNamingStrategy.

→ Ссылка