Spring Boot + JPA: Анотація назви стовпців ігнорується


121

У мене є програма 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вирішив проблему (назва стовпця взята з анотації стовпців).

І все-таки моє запитання: чому без nameing_strategy, встановленого на EJB3NamingStrategyJPA, ігнорується анотація стовпців? Можливо, сплячий діалект має щось спільне з цим? Я підключаюся до MS SQL 2014 Express, і мої журнали містять:

Unknown Microsoft SQL Server major version [12] using SQL Server 2000 dialect
Using dialect: org.hibernate.dialect.SQLServerDialect 

1
Це питання про явному вигляді при умови , ім'я стовпця бути змінений , а не ігнорували . Це зводиться до того, що це буде виконано замість очікуваного прозорого варіанту . Hibernate може насправді ігнорувати @Column(name="...")анотації, наприклад, коли ви використовуєте інший, ніж очікуваний тип доступу, але це не так.
Властиміл Овчачик

Відповіді:


163

Для 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

30
spring.jpa.hibernate.naming.physical-strategy = org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl, тільки ця властивість потрібна, щоб зберегти ім’я таким, яким воно є.
abhishek Ringia

1
У мене була така ж проблема, і додавши ці 2 властивості, це вирішило для мене. Я бігаю Весняний черевик 1.4.3
Йоган

1
Це єдине рішення, яке працювало і для мене. Я використовую Spring Boot 1.4.2
Sanjiv Jivan

Я використовую Spring Boot 1.5.9. РЕЛІЗ, ця публікація працює для мене
IcyBrk

Дивовижно .. Мені було цікаво, чому вона ігнорує мою анотацію @Column. Нарешті це мені допомогло. Мені здається, що це або помилка, або функція відсутня.
Раджу Пенумаца

86

За замовчуванням Spring використовує org.springframework.boot.orm.jpa.SpringNamingStrategyдля генерації імен таблиць. Це дуже тонке розширення org.hibernate.cfg.ImprovedNamingStrategy. tableNameМетод в цьому класі передається вихідне Stringзначення , але не знає , якщо вона виходить від @Column.nameатрибута або якщо воно неявно генерується з імені поля.

ImprovedNamingStrategyБуде конвертувати CamelCaseв SNAKE_CASEякому як EJB3NamingStrategyраз використовує ім'я таблиці без змін.

Якщо ви не хочете змінювати стратегію іменування, ви завжди можете просто вказати назву стовпця в малому регістрі:

@Column(name="testname")

1
Привіт, Філ. За допомогою весняного завантаження я додаю spring.jpa.hibernate.naming.strategy: org.hibernate.cfg.EJB3NamingStrategy. Але це схоже не працює для мене. можеш допомогти мені?
BeeNoisy

Важливою частиною відповіді є введення імені в малі регістри! Я раджу не змінювати тактику, а ставити назву в нижньому регістрі, оскільки назва стовпця не відрізняється від регістру!
loicmathieu

31

Здається, що

@Column (назва = "..")

повністю ігнорується, якщо немає

spring.jpa.hibernate.naming_strategy = org.hibernate.cfg.EJB3NamingStrategy

вказано, тому для мене це помилка.

Я витратив кілька годин, намагаючись з’ясувати, чому @Column (name = "..") ігнорували.


4
У мене була така ж проблема. Сюди я додав звіт про проблему: github.com/spring-projects/spring-boot/isissue/2129
Kacper86

Дуже дякую. Втрачено приблизно за день, щоб вказати моє додаток на існуючий db.
Дмитро Єрохін

Це насправді не ігнорується, лише задана стратегія іменування весни за замовчуванням застосовується до заданого атрибута імені. Читайте відповідь @PhilWebb
Мішель

16

Стратегія за замовчуванням @Column(name="TestName")буде test_name, це правильна поведінка!

Якщо TestNameу вашій базі є стовпець, названий, слід змінити анотацію стовпця на @Column(name="testname").

Це працює, тому що базу даних не хвилює, якщо ви називаєте свій стовпець TestName або тестове ім'я ( назви стовпців не залежать від регістру !! ).

Але будьте обережні, те ж саме не стосується імен бази даних та таблиць, які чутливі до регістру в системах Unix, але чутливі до регістру в системах Windows (факт, що, ймовірно, тримав багато людей уночі, працюючи над Windows, але розгортаючись на Linux :))


3
1. Насправді це неправда, імена стовпців можуть бути чутливими до регістру залежно від конфігурації бази даних, яку ви використовуєте ... 2. @ Назва колонки - як підказує ім'я, повинно бути місце для надання імені стовпця бази даних, а не якогось ідентифікатора, який є рамкою зміниться під час виконання ..
Каміль

1. Дякую, чи можете ви навести приклад db, коли назви стовпців за замовчуванням залежать від регістру? 2. Насправді @Column дає нам логічні імена, які визначаються фізичними іменами PhysicalNamingStrategy, принаймні так, як видається, пише док: docs.jboss.org/hibernate/orm/5.1/userguide/html_single/chapters/…
Орхан

2
1. Вибачте, я не можу, як мені байдуже, який у нього є за замовчуванням, мені все одно, які налаштування встановлює DBA на тому, який я використовую. 2. Це, на жаль, вірно - це лише моя особиста думка, що такий підхід невірний, оскільки він змушує задуматися або про те, як ім’я було б відображено в стовпчик в кінці, або яку стратегію іменування використовувати, яка не стосується наданих імен.
Каміль

1
Щоправда, це було б найбільш інтуїтивним рішенням, і, звичайно, краща документація щодо цього не зашкодила б.
Орхан

явно встановлене ім'я стовпця повинно за будь-яких умов перекривати неявно генерований. Якщо це не так, це помилка в реалізації JPA.
jwenting

13

Єдине рішення, яке працювало для мене, - це те, яке розмістив 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 вносить у сплячку, щоб налаштувати стратегію іменування.

      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)

6

teteArg , дуже дякую Просто додана інформація, тому кожен, натрапивши на це питання, зможе зрозуміти, чому.

Що сказав teteArg , зазначено у загальних властивостях Spring Boot: http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html

Мабуть, spring.jpa.hibernate.naming.strategy не підтримується властивістю для впровадження Spring JPA з використанням Hibernate 5.


Я радий допомогти вам
teteArg

4

Виявляється, мені просто потрібно перетворити @columnім'я testName на всі маленькі літери, оскільки це було спочатку в корпусі верблюда.

Хоча я не зміг використати офіційну відповідь, питання могло допомогти мені вирішити свою проблему, давши мені знати, що слід досліджувати.

Змінити:

@Column(name="testName")
private String testName;

До:

@Column(name="testname")
private String testName;

3

Якщо ви хочете використовувати @Column (...), тоді використовуйте маленькі літери завжди, навіть якщо ваш справжній стовпець DB знаходиться у регістрі верблюда.

Приклад: Якщо використовується власне ім'я стовпця БД TestName:

  @Column(name="testname") //all small-case

Якщо вам це не подобається, просто змініть фактичну назву стовпця БД на: test_name


1

У моєму випадку анотація була на методі getter () замість самого поля (перенесеного із застарілої програми).

Весна ігнорує примітки і в цьому випадку, але не скаржиться. Рішення полягало в тому, щоб перемістити його в поле замість геттера.


1
дякую за оновлення Дійсна інформація дійсно.
jwenting
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.