Spring Boot + JPA: аннотацию имени столбца игнорируется
У меня есть приложение Spring Boot с зависимостью spring-boot-starter-data-jpa
. У моего класса сущности есть аннотация столбца с именем столбца. Например:
@Column(name="TestName")
private String testName;
SQL, созданный этим созданным test_name
качестве имени столбца. После поиска решения я обнаружил, что spring.jpa.hibernate.naming_strategy=org.hibernate.cfg.EJB3NamingStrategy
решил проблему (имя столбца взято из аннотации столбца).
Тем не менее мой вопрос заключается в том, почему без naming_strategy, установленного в EJB3NamingStrategy
JPA игнорирует аннотации столбцов? Может быть, спящий диалект имеет к этому какое-то отношение? Я подключаюсь к MS SQL 2014 Express и мои журналы содержат:
Unknown Microsoft SQL Server major version [12] using SQL Server 2000 dialect
Using dialect: org.hibernate.dialect.SQLServerDialect
Ответы
Ответ 1
Для hibernate5 я решил эту проблему, поставив следующие строки в файле application.properties:
spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
Ответ 2
По умолчанию Spring использует org.springframework.boot.orm.jpa.SpringNamingStrategy
для генерации имен таблиц. Это очень тонкое расширение org.hibernate.cfg.ImprovedNamingStrategy
. Метод tableName
в этом классе передается исходным значением String
, но он не знает, исходит ли он из атрибута @Column.name
или если он неявно генерируется из имени поля.
ImprovedNamingStrategy
преобразует CamelCase
в SNAKE_CASE
, где, поскольку EJB3NamingStrategy
просто использует имя таблицы без изменений.
Если вы не хотите менять стратегию именования, вы всегда можете просто указать имя столбца в нижнем регистре:
@Column(name="testname")
Ответ 3
Кажется, что
@Column (name= ".." )
полностью игнорируется, если не существует
spring.jpa.hibernate.naming_strategy = org.hibernate.cfg.EJB3NamingStrategy
поэтому для меня это ошибка.
Я потратил несколько часов, пытаясь понять, почему @Column (name= ".." ) был проигнорирован.
Ответ 4
Единственное решение, которое сработало для меня, было тем, что было опубликовано teteArg выше. Я нахожусь в Spring Boot 1.4.2 w/Hibernate 5. А именно
spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
Для дополнительной информации я отправляю трассировку вызова так, чтобы ее ясное, что вызывает Spring, превращается в Hibernate для настройки стратегии именования.
at org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl.toPhysicalColumnName(PhysicalNamingStrategyStandardImpl.java:46)
at org.hibernate.cfg.Ejb3Column.redefineColumnName(Ejb3Column.java:309)
at org.hibernate.cfg.Ejb3Column.initMappingColumn(Ejb3Column.java:234)
at org.hibernate.cfg.Ejb3Column.bind(Ejb3Column.java:206)
at org.hibernate.cfg.Ejb3DiscriminatorColumn.buildDiscriminatorColumn(Ejb3DiscriminatorColumn.java:82)
at org.hibernate.cfg.AnnotationBinder.processSingleTableDiscriminatorProperties(AnnotationBinder.java:797)
at org.hibernate.cfg.AnnotationBinder.bindClass(AnnotationBinder.java:561)
at org.hibernate.boot.model.source.internal.annotations.AnnotationMetadataSourceProcessorImpl.processEntityHierarchies(AnnotationMetadataSourceProcessorImpl.java:245)
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess$1.processEntityHierarchies(MetadataBuildingProcess.java:222)
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:265)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:847)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:874)
at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:60)
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:353)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:373)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:362)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1642)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1579)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
- locked <0x1687> (a java.util.concurrent.ConcurrentHashMap)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1081)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:856)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:542)
- locked <0x1688> (a java.lang.Object)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:761)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:371)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:315)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1186)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1175)
Ответ 5
Стратегия по умолчанию для @Column(name="TestName")
будет test_name
, это правильное поведение!
Если у вас есть столбец с именем TestName
в вашей базе данных, вы должны изменить аннотацию столбца на @Column(name="TestName")
.
Это работает, потому что базе данных все равно, назовете ли вы имя столбца TestName или testname (имена столбцов нечувствительны к регистру!!).
Но будьте осторожны, то же самое не относится к именам баз данных и таблицам, которые чувствительны к регистру в Unix-системах, но с учетом чувствительности к системам Windows (тот факт, что, вероятно, многие люди просыпались ночью, работая над окнами, но развертывание на Linux:))
Ответ 6
teteArg, большое вам спасибо.
Просто добавленная информация, поэтому все, кто сталкивается с этим вопросом, смогут понять, почему.
Что teteArg указано в Spring Общие свойства загрузки: < а2 >
По-видимому, spring.jpa.hibernate.naming.strategy не является поддерживаемым свойством для реализации Spring JPA с использованием Hibernate 5.
Ответ 7
Единственное, что сработало для меня, это наличие двух строк кода, как указано выше:
spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
Только одна линия, предложенная ncaralicea, не работала для меня
Ответ 8
Если вы хотите использовать @Column (...), всегда используйте строчные буквы, даже если ваш фактический столбец БД находится в верблюжьем регистре.
Пример: если ваше фактическое имя столбца БД - TestName
используйте:
@Column(name="testname") //all small-case
Если вам это не нравится, просто измените фактическое имя столбца БД на: test_name
Ответ 9
В моем случае, аннотация была на методе getter() вместо самого поля (перенесено из унаследованного приложения).
Spring игнорирует аннотацию и в этом случае, но не жалуется. Решение состояло в том, чтобы переместить это в область вместо добытчика.
Ответ 10
Оказывается, мне просто нужно преобразовать @column
name testName во все строчные буквы, так как изначально это было в случае верблюда.
Хотя я не смог использовать официальный ответ, этот вопрос помог мне решить мою проблему, сообщив мне, что нужно расследовать.
Изменить:
@Column(name="testName")
private String testName;
Для того, чтобы:
@Column(name="testname")
private String testName;