Spring Boot + JPA: Anmerkung zum Spaltennamen ignoriert

120

Ich habe eine Spring Boot-Anwendung mit Abhängigkeit spring-boot-starter-data-jpa. Meine Entitätsklasse hat eine Spaltenanmerkung mit einem Spaltennamen. Beispielsweise:

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

SQL, das dadurch generiert wird, wird test_nameals Spaltenname erstellt. Nachdem ich nach einer Lösung gesucht habe, habe ich festgestellt, dass spring.jpa.hibernate.naming_strategy=org.hibernate.cfg.EJB3NamingStrategydas Problem behoben ist (der Spaltenname stammt aus der Spaltenanmerkung).

Meine Frage ist jedoch, warum ohne die auf EJB3NamingStrategyJPA gesetzte Namensstrategie die Spaltenanmerkung ignoriert wird. Vielleicht hat der Dialekt im Winterschlaf etwas damit zu tun? Ich stelle eine Verbindung zu MS SQL 2014 Express her und meine Protokolle enthalten:

Unknown Microsoft SQL Server major version [12] using SQL Server 2000 dialect
Using dialect: org.hibernate.dialect.SQLServerDialect 
Kamil
quelle
1
Bei dieser Frage geht es darum, dass der explizit angegebene Spaltenname geändert und nicht ignoriert wird . Es läuft darauf hinaus, dass dies anstelle der erwarteten transparenten Variante ausgeführt wird . Im Ruhezustand werden @Column(name="...")Anmerkungen möglicherweise ignoriert , z. B. wenn Sie einen anderen als den erwarteten Zugriffstyp verwenden. Dies ist hier jedoch nicht der Fall.
Vlastimil Ovčáčík

Antworten:

163

Für den Ruhezustand5 habe ich dieses Problem gelöst, indem ich die nächsten Zeilen in meine Datei application.properties eingefügt habe:

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
quelle
30
spring.jpa.hibernate.naming.physical-Strategy = org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl, nur diese Eigenschaft ist erforderlich, um den Namen unverändert zu lassen.
Abhishek Ringsia
1
Ich hatte das gleiche Problem und das Hinzufügen dieser 2 Eigenschaften löste es für mich. Ich verwende Spring Boot 1.4.3
Johan
1
Dies ist die einzige Lösung, die auch für mich funktioniert hat. Ich benutze Spring Boot 1.4.2
Sanjiv Jivan
Ich benutze Spring Boot 1.5.9.RELEASE, dieser Beitrag funktioniert für mich
IcyBrk
Genial. Ich habe mich gefragt, warum meine @ Column-Annotation ignoriert wurde. Endlich hat mir das geholfen. Für mich ist dies entweder ein Fehler oder eine fehlende Funktionalität.
Raju Penumatsa
85

Standardmäßig org.springframework.boot.orm.jpa.SpringNamingStrategygeneriert Spring Tabellennamen. Dies ist eine sehr dünne Erweiterung von org.hibernate.cfg.ImprovedNamingStrategy. Der tableNameMethode in dieser Klasse wird ein StringQuellwert übergeben, es ist jedoch nicht bekannt, ob sie von einem @Column.nameAttribut stammt oder implizit aus dem Feldnamen generiert wurde.

Das ImprovedNamingStrategywird CamelCasein SNAKE_CASEwhere konvertiert , da der EJB3NamingStrategygerade den Tabellennamen unverändert verwendet.

Wenn Sie die Namensstrategie nicht ändern möchten, können Sie Ihren Spaltennamen immer in Kleinbuchstaben angeben:

@Column(name="testname")
Phil Webb
quelle
1
Hallo Phil. Durch die Verwendung von Spring Boot habe ich spring.jpa.hibernate.naming.strategy hinzugefügt: org.hibernate.cfg.EJB3NamingStrategy. Aber es sieht so aus, als würde es bei mir nicht funktionieren. können Sie mir helfen?
BeeNoisy
Der wichtige Teil der Antwort besteht darin, den Namen in Kleinbuchstaben zu schreiben! Ich rate, die Strategie nicht zu ändern, aber den Namen in Kleinbuchstaben zu setzen, da bei Spaltennamen die Groß- und Kleinschreibung nicht berücksichtigt wird!
Loicmathieu
31

Es scheint, dass

@Column (name = "..")

wird vollständig ignoriert, es sei denn

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

angegeben, also für mich ist dies ein Fehler.

Ich habe ein paar Stunden damit verbracht herauszufinden, warum @Column (name = "..") ignoriert wurde.

ncaralicea
quelle
4
Ich hatte das gleiche Problem. Ich habe hier einen
Problembericht
Vielen Dank. Ich habe ungefähr einen Tag verloren, um meine App auf eine vorhandene Datenbank zu verweisen.
Dmitry Erokhin
Es wird eigentlich nicht ignoriert, nur die Standard-Frühlingsbenennungsstrategie wird auf das angegebene Namensattribut angewendet. Lesen Sie @ PhilWebb Antwort
Michel Feldheim
15

Die Standardstrategie für @Column(name="TestName")wird sein test_name, dies ist korrektes Verhalten!

Wenn TestNameIhre Datenbank eine Spalte mit dem Namen enthält , sollten Sie die Spaltenanmerkung in ändern @Column(name="testname").

Dies funktioniert, da es der Datenbank egal ist, ob Sie Ihre Spalte Testname oder Testname benennen ( Spaltennamen unterscheiden nicht zwischen Groß- und Kleinschreibung !! ).

Beachten Sie jedoch, dass dies nicht für Datenbanknamen und Tabellennamen gilt, bei denen auf Unix-Systemen zwischen Groß- und Kleinschreibung unterschieden wird, auf Windows-Systemen jedoch zwischen Groß- und Kleinschreibung (die Tatsache, dass wahrscheinlich viele Leute nachts wach gehalten haben, unter Windows gearbeitet haben, aber unter Linux bereitgestellt wurden :))

Orhan
quelle
3
1. Eigentlich stimmt das nicht, Spaltennamen können abhängig von der Konfiguration der verwendeten Datenbank zwischen Groß- und Kleinschreibung unterscheiden ... 2. @ Spaltenname - wie der Name schon sagt, sollte ein Ort sein, an dem der Name der Datenbankspalte angegeben werden kann, nicht eine Kennung, die ein Framework enthält wird sich zur Laufzeit ändern ..
Kamil
1. Danke, können Sie ein Beispiel für db geben, bei dem Spaltennamen standardmäßig zwischen Groß- und Kleinschreibung unterscheiden? 2. Tatsächlich gibt @Column logische Namen an, die von PhysicalNamingStrategy in physische Namen aufgelöst werden. Zumindest scheint dies das zu sein, was das Dokument sagt: docs.jboss.org/hibernate/orm/5.1/userguide/html_single/chapters/…
Orhan
2
1. Tut mir leid, ich kann nicht, da es mir egal ist, welches es standardmäßig hat. Es ist mir egal, welche Einstellungen von DBA für das von mir verwendete festgelegt werden. 2. Das ist leider wahr - es ist nur meine persönliche Meinung, dass dieser Ansatz falsch ist, da er mich dazu zwingt, darüber nachzudenken oder darüber nachzudenken, wie der Name am Ende einer Spalte zugeordnet wird oder welche Benennungsstrategie verwendet werden soll, die die angegebenen Namen nicht berührt.
Kamil
1
Das wäre zwar die intuitivste Lösung, und eine bessere Dokumentation würde natürlich nicht schaden.
Orhan
Ein explizit festgelegter Spaltenname sollte unter allen Umständen einen implizit generierten überschreiben. Wenn dies nicht der Fall ist, ist dies ein Fehler in der JPA-Implementierung.
Jwenting
13

Die einzige Lösung, die für mich funktioniert hat, war die von teteArg oben. Ich bin auf Spring Boot 1.4.2 mit Ruhezustand 5. Nämlich

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

Für zusätzliche Informationen veröffentliche ich die Anrufverfolgung, damit klar ist, welche Anrufe Spring in den Ruhezustand tätigt, um die Namensstrategie einzurichten.

      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
quelle
6

teteArg , vielen Dank. Nur eine zusätzliche Information, damit jeder, der auf diese Frage stößt, verstehen kann, warum.

Was teteArg sagte, wird in den allgemeinen Eigenschaften von Spring Boot angegeben: http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html

Anscheinend ist spring.jpa.hibernate.naming.strategy keine unterstützte Eigenschaft für die Spring JPA-Implementierung mit Hibernate 5.

Romeo Jr. Maranan
quelle
Ich bin
4

Es stellt sich heraus, dass ich nur den @columnNamen testName in alle kleinen Buchstaben konvertieren muss, da es sich ursprünglich um einen Kamelfall handelte.

Obwohl ich die offizielle Antwort nicht verwenden konnte, konnte mir die Frage helfen, mein Problem zu lösen, indem sie mir mitteilte, was ich untersuchen sollte.

Veränderung:

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

Zu:

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

Wenn Sie @Column (...) verwenden möchten, verwenden Sie immer Kleinbuchstaben, obwohl sich Ihre eigentliche DB-Spalte in Kamelbuchstaben befindet.

Beispiel: Wenn Ihr tatsächlicher DB-Spaltenname lautet, TestNameverwenden Sie:

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

Wenn Ihnen das nicht gefällt, ändern Sie einfach den tatsächlichen DB-Spaltennamen in: test_name

Dean
quelle
1

In meinem Fall befand sich die Annotation auf der Methode getter () anstelle des Felds selbst (portiert von einer Legacy-Anwendung).

Spring ignoriert die Anmerkung auch in diesem Fall, beschwert sich aber nicht. Die Lösung bestand darin, es anstelle des Getters auf das Feld zu bringen.

java-addict301
quelle
1
Danke für das Update. Wertvolle Informationen.
Jwenting