Spring Boot + JPA: se ignora la anotación del nombre de la columna

121

Tengo una aplicación Spring Boot con dependencia spring-boot-starter-data-jpa. Mi clase de entidad tiene una anotación de columna con un nombre de columna. Por ejemplo:

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

SQL generado por esto creado test_namecomo el nombre de las columnas. Después de buscar una solución, encontré que spring.jpa.hibernate.naming_strategy=org.hibernate.cfg.EJB3NamingStrategyresolvió el problema (el nombre de la columna se toma de la anotación de la columna).

Aún así, mi pregunta es ¿por qué sin naming_strategy establecido en EJB3NamingStrategyJPA se ignora la anotación de columna? ¿Quizás el dialecto de hibernación tenga algo que ver con eso? Me estoy conectando a MS SQL 2014 Express y mis registros contienen:

Unknown Microsoft SQL Server major version [12] using SQL Server 2000 dialect
Using dialect: org.hibernate.dialect.SQLServerDialect 
Kamil
fuente
1
Esta pregunta trata sobre la modificación del nombre de columna proporcionado explícitamente en lugar de ignorarse . Todo se reduce a que esto se ejecute en lugar de la variante transparente esperada . Hibernate puede ignorar la @Column(name="...")anotación, por ejemplo, cuando usa un tipo de acceso diferente al esperado, pero ese no es el caso aquí.
Vlastimil Ovčáčík

Respuestas:

163

Para hibernate5 resolví este problema colocando las siguientes líneas en mi archivo 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
teteArg
fuente
30
spring.jpa.hibernate.naming.physical-strategy = org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl, solo esta propiedad es necesaria para mantener el nombre como está.
abhishek ringsia
1
Tuve el mismo problema y agregar esas 2 propiedades lo resolvió por mí. Estoy ejecutando Spring Boot 1.4.3
Johan
1
Esta es la única solución que también me funcionó. Estoy usando Spring Boot 1.4.2
Sanjiv Jivan
Estoy usando Spring Boot 1.5.9.RELEASE, esta publicación me funciona
IcyBrk
Impresionante ... Me preguntaba por qué ignoraba mi anotación @Column. Finalmente esto me ayudó. Para mí, siento que esto es un error o una funcionalidad faltante.
Raju Penumatsa
86

Por defecto, Spring usa org.springframework.boot.orm.jpa.SpringNamingStrategypara generar nombres de tablas. Esta es una extensión muy delgada de org.hibernate.cfg.ImprovedNamingStrategy. Al tableNamemétodo de esa clase se le pasa un Stringvalor fuente , pero no sabe si proviene de un @Column.nameatributo o si se ha generado implícitamente a partir del nombre del campo.

El ImprovedNamingStrategyse convertirá CamelCasea SNAKE_CASEdonde, ya que EJB3NamingStrategysolo usa el nombre de la tabla sin cambios.

Si no desea cambiar la estrategia de nomenclatura, siempre puede especificar el nombre de su columna en minúsculas:

@Column(name="testname")
Phil Webb
fuente
1
Hola, Phil. Al usar Spring Boot, agregué spring.jpa.hibernate.naming.strategy: org.hibernate.cfg.EJB3NamingStrategy. Pero parece que no me funciona. ¿me puedes ayudar?
BeeNoisy
¡La parte importante de la respuesta es poner el nombre en minúsculas! Aconsejo no cambiar la estrategia, pero poner el nombre en minúsculas ya que el nombre de la columna no distingue entre mayúsculas y minúsculas.
loicmathieu
31

Parece que

@Column (nombre = "..")

se ignora por completo a menos que haya

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

especificado, entonces para mí esto es un error.

Pasé algunas horas tratando de averiguar por qué se ignoró @Column (name = "..").

ncaralicea
fuente
4
Yo tuve el mismo problema. Agregué
Kacper86
Muchas gracias. Perdí un día para apuntar mi aplicación a una base de datos existente.
Dmitry Erokhin
En realidad, no se ignora, solo se aplica la estrategia de nomenclatura de primavera predeterminada en el atributo de nombre dado. Lea la respuesta de @PhilWebb
Michel Feldheim
16

La estrategia predeterminada para @Column(name="TestName")será test_name, ¡este es el comportamiento correcto!

Si tiene una columna nombrada TestNameen su base de datos, debe cambiar la anotación de columna a @Column(name="testname").

Esto funciona porque a la base de datos no le importa si nombra su columna TestName o testname (los nombres de las columnas no distinguen entre mayúsculas y minúsculas !! ).

Pero cuidado, no se aplica lo mismo para el nombre de la base de datos y los nombres de las tablas, que distinguen entre mayúsculas y minúsculas en los sistemas Unix pero sí en los sistemas Windows (el hecho de que probablemente mantuvo a mucha gente despierta por la noche, trabajando en Windows pero desplegando en Linux :))

Orhan
fuente
3
1. En realidad, eso no es cierto, los nombres de las columnas pueden distinguir entre mayúsculas y minúsculas dependiendo de la configuración de la base de datos que esté utilizando ... 2. @ Nombre de la columna: como sugiere el nombre, debe ser un lugar para proporcionar el nombre de la columna de la base de datos, no un identificador que sea un marco. cambiará durante el tiempo de ejecución ..
Kamil
1. Gracias, ¿puede dar un ejemplo de db donde los nombres de columna distinguen entre mayúsculas y minúsculas de forma predeterminada? 2. En realidad, @Column nos da nombres lógicos que se resuelven en nombres físicos mediante PhysicalNamingStrategy, al menos eso parece ser lo que dice el documento: docs.jboss.org/hibernate/orm/5.1/userguide/html_single/chapters/…
Orhan
2
1.Lo siento, no puedo, ya que no me importa cuál lo tenga de forma predeterminada, me importa qué configuración establece el DBA en el que estoy usando. 2. Desafortunadamente, eso es cierto; es solo mi opinión personal que este enfoque es incorrecto, ya que me obliga a pensar en cómo se asignaría el nombre a la columna al final, o qué estrategia de nomenclatura usar que no toque los nombres proporcionados.
Kamil
1
Es cierto que esa sería la solución más intuitiva y, por supuesto, una mejor documentación sobre esto no estaría de más.
Orhan
un nombre de columna establecido explícitamente debe, en todas las condiciones, anular uno generado implícitamente. Si no es así, es un error en la implementación de JPA.
Jueves el
13

La única solución que funcionó para mí fue la publicada por teteArg arriba. Estoy en Spring Boot 1.4.2 con Hibernate 5. A saber

spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl

Para obtener información adicional, estoy publicando el seguimiento de llamadas para que quede claro qué llamadas está haciendo Spring en Hibernate para configurar la estrategia de nombres.

      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)
Sanjiv Jivan
fuente
6

teteArg , muchas gracias. Solo una información adicional para que todos los que se encuentren con esta pregunta podrán entender por qué.

Lo que dijo teteArg se indica en las propiedades comunes de Spring Boot: http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html

Aparentemente, spring.jpa.hibernate.naming.strategy no es una propiedad compatible para la implementación de Spring JPA usando Hibernate 5.

Romeo Jr Maranan
fuente
Estoy feliz de ayudarlo
teteArg
4

Resulta que solo tengo que convertir el @columnnombre testName a todas las letras minúsculas, ya que inicialmente estaba en caja camel.

Aunque no pude usar la respuesta oficial, la pregunta pudo ayudarme a resolver mi problema al permitirme saber qué investigar.

Cambio:

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

A:

@Column(name="testname")
private String testName;
Mohammad Cali
fuente
3

Si desea usar @Column (...), use letras en minúsculas siempre, aunque su columna DB real esté en camel-case.

Ejemplo: si su nombre de columna de base de datos real es TestName, utilice:

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

Si no le gusta eso, simplemente cambie el nombre real de la columna de la base de datos a: test_name

Decano
fuente
1

En mi caso, la anotación estaba en el método getter () en lugar del campo en sí (portado desde una aplicación heredada).

Spring también ignora la anotación en este caso, pero no se queja. La solución fue moverlo al campo en lugar del getter.

java-addict301
fuente
1
gracias por la actualización. Ciertamente información valiosa.
Jueves el