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.