Spring Boot + JPA: annotazione del nome della colonna ignorata


121

Ho un'applicazione Spring Boot con dipendenza spring-boot-starter-data-jpa. La mia classe di entità ha un'annotazione di colonna con un nome di colonna. Per esempio:

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

SQL generato da questo creato test_namecome nome delle colonne. Dopo aver cercato una soluzione, ho scoperto che ha spring.jpa.hibernate.naming_strategy=org.hibernate.cfg.EJB3NamingStrategyrisolto il problema (il nome della colonna è preso dall'annotazione della colonna).

Tuttavia, la mia domanda è perché senza naming_strategy impostato su EJB3NamingStrategyJPA si ignora l'annotazione di colonna? Forse il dialetto ibernato ha qualcosa a che fare con questo? Mi sto collegando a MS SQL 2014 Express e i miei log contengono:

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

1
Questa domanda riguarda il nome della colonna fornito in modo esplicito che viene alterato anziché ignorato . Si riduce a questa esecuzione invece della prevista variante trasparente . Hibernate può effettivamente ignorare l' @Column(name="...")annotazione, ad esempio quando si utilizza un tipo di accesso diverso da quello previsto, ma non è questo il caso qui.
Vlastimil Ovčáčík

Risposte:


163

Per hibernate5 ho risolto questo problema inserendo le righe successive nel mio file 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, solo questa proprietà è richiesta per mantenere il nome così com'è.
abhishek ringsia

1
Ho avuto lo stesso problema e l'aggiunta di quelle 2 proprietà lo ha risolto per me. Sto eseguendo Spring Boot 1.4.3
Johan

1
Questa è l'unica soluzione che ha funzionato anche per me. Sto usando Spring Boot 1.4.2
Sanjiv Jivan

Sto usando Spring Boot 1.5.9.RELEASE, questo post funziona per me
IcyBrk

Fantastico .. Mi chiedevo perché ignorasse la mia annotazione @Column. Alla fine questo mi ha aiutato. Per me, sento che questo è un bug o una funzionalità mancante.
Raju Penumatsa

86

Per impostazione predefinita, Spring utilizza org.springframework.boot.orm.jpa.SpringNamingStrategyper generare i nomi delle tabelle. Questa è un'estensione molto sottile di org.hibernate.cfg.ImprovedNamingStrategy. Al tableNamemetodo in quella classe viene passato un Stringvalore sorgente ma non è a conoscenza se proviene da un @Column.nameattributo o se è stato implicitamente generato dal nome del campo.

Il ImprovedNamingStrategyconvertirà CamelCasea SNAKE_CASEdove, come la EJB3NamingStrategyutilizza solo il nome della tabella invariata.

Se non desideri modificare la strategia di denominazione, puoi sempre specificare il nome della colonna in minuscolo:

@Column(name="testname")

1
Ciao, Phil. Utilizzando lo spring boot, ho aggiunto spring.jpa.hibernate.naming.strategy: org.hibernate.cfg.EJB3NamingStrategy. Ma sembra che non funzioni per me. Mi potete aiutare?
BeeNoisy

La parte importante della risposta è mettere il nome in minuscolo! Consiglio di non cambiare la strategia ma di mettere il nome in minuscolo in quanto i nomi delle colonne non fanno distinzione tra maiuscole e minuscole!
loicmathieu

31

Sembra che

@Column (name = "..")

è completamente ignorato a meno che non ci sia

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

specificato, quindi per me questo è un bug.

Ho trascorso alcune ore cercando di capire perché @Column (name = "..") è stato ignorato.


4
Ho avuto lo stesso problema. Ho aggiunto un rapporto sul problema qui: github.com/spring-projects/spring-boot/issues/2129
Kacper86

Molte grazie. Ho perso circa un giorno per indirizzare la mia app al db esistente.
Dmitry Erokhin

In realtà non viene ignorato, solo la strategia di denominazione della molla predefinita viene applicata all'attributo del nome specificato. Leggi la risposta di @PhilWebb
Michel Feldheim

16

La strategia predefinita per @Column(name="TestName")sarà test_name, questo è il comportamento corretto!

Se hai una colonna denominata TestNamenel tuo database, dovresti cambiare l'annotazione della colonna in @Column(name="testname").

Funziona perché al database non interessa se assegni il nome alla colonna TestName o testname (i nomi delle colonne non fanno distinzione tra maiuscole e minuscole !! ).

Ma attenzione, lo stesso non vale per il nome del database e per i nomi delle tabelle, che fanno distinzione tra maiuscole e minuscole su sistemi Unix ma maiuscole e minuscole su sistemi Windows (il fatto che probabilmente teneva sveglie molte persone di notte, lavorando su Windows ma distribuendo su Linux :))


3
1. In realtà non è vero, i nomi delle colonne possono fare distinzione tra maiuscole e minuscole a seconda della configurazione del database che stai utilizzando ... 2. @Column name - come suggerisce il nome dovrebbe essere un posto per fornire il nome della colonna del database, non un identificatore che un framework cambierà durante il runtime ..
Kamil

1. Grazie, puoi fornire un esempio di db in cui i nomi delle colonne fanno distinzione tra maiuscole e minuscole per impostazione predefinita? 2. In realtà @Column ci fornisce nomi logici che vengono risolti in nomi fisici da PhysicalNamingStrategy, almeno questo sembra essere ciò che dice il documento: docs.jboss.org/hibernate/orm/5.1/userguide/html_single/chapters/…
Orhan

2
1.Mi dispiace di non poterlo fare perché non mi interessa quale ce l'ha per impostazione predefinita, mi interessa quali impostazioni sono impostate da DBA su quello che sto usando. 2. Sfortunatamente è vero - è solo la mia opinione personale che questo approccio sia sbagliato in quanto mi costringe a pensare o a come il nome verrebbe mappato alla colonna alla fine, o quale strategia di denominazione utilizzare che non tocchi i nomi forniti.
Kamil

1
È vero, questa sarebbe la soluzione più intuitiva e, naturalmente, una migliore documentazione su questo non guasterebbe.
Orhan

un nome di colonna impostato in modo esplicito dovrebbe in tutte le condizioni sovrascrivere uno generato implicitamente. In caso contrario, è un bug nell'implementazione JPA.
jwenting

13

L'unica soluzione che ha funzionato per me è stata quella pubblicata da teteArg sopra. Sono su Spring Boot 1.4.2 con Hibernate 5. Vale a dire

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

Per ulteriori informazioni, sto postando la traccia delle chiamate in modo che sia chiaro ciò che le chiamate Spring stanno facendo in Hibernate per impostare la strategia di denominazione.

      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 , grazie mille. Solo un'informazione aggiuntiva così, tutti coloro che si imbattono in questa domanda saranno in grado di capire perché.

Ciò che ha detto teteArg è indicato nelle proprietà comuni di Spring Boot: http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html

Apparentemente, spring.jpa.hibernate.naming.strategy non è una proprietà supportata per l'implementazione di Spring JPA utilizzando Hibernate 5.


Sono felice di aiutarti
teteArg

4

Si scopre che devo solo convertire il @columnnome testName in tutte le lettere minuscole, poiché inizialmente era in caso di cammello.

Sebbene non fossi in grado di utilizzare la risposta ufficiale, la domanda è stata in grado di aiutarmi a risolvere il mio problema facendomi sapere su cosa indagare.

Modificare:

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

Per:

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

3

Se vuoi usare @Column (...), usa sempre lettere minuscole anche se la tua colonna DB attuale è in camel-case.

Esempio: se il nome effettivo della colonna DB è TestNamequindi utilizzare:

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

Se non ti piace, cambia semplicemente il nome effettivo della colonna DB in: test_name


1

Nel mio caso, l'annotazione era sul metodo getter () invece del campo stesso (portato da un'applicazione legacy).

Anche in questo caso Spring ignora l'annotazione ma non si lamenta. La soluzione era spostarlo sul campo invece che sul getter.


1
grazie per l'aggiornamento. Informazioni preziose davvero.
jwenting
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.