J'ai une application Spring Boot avec dépendance spring-boot-starter-data-jpa
. Ma classe d'entités comporte une annotation de colonne avec un nom de colonne. Par exemple:
@Column(name="TestName")
private String testName;
Le code SQL généré par ceci a créé test_name
en tant que nom de colonne. Après avoir cherché une solution, j'ai découvert que spring.jpa.hibernate.naming_strategy=org.hibernate.cfg.EJB3NamingStrategy
avait résolu le problème (le nom de colonne est tiré de l'annotation de colonne).
Néanmoins, ma question est la suivante: pourquoi, sans naming_strategy défini sur EJB3NamingStrategy
, JPA ignore les annotations de colonne? Peut-être que le dialecte en veille prolongée a quelque chose à voir avec cela? Je me connecte à MS SQL 2014 Express et mes journaux contiennent:
Unknown Microsoft SQL Server major version [12] using SQL Server 2000 dialect
Using dialect: org.hibernate.dialect.SQLServerDialect
Pour hibernate5, j'ai résolu ce problème en ajoutant les lignes suivantes dans mon fichier 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
Par défaut, Spring utilise org.springframework.boot.orm.jpa.SpringNamingStrategy
pour générer les noms de table. C'est une extension très fine de org.hibernate.cfg.ImprovedNamingStrategy
. La méthode tableName
de cette classe reçoit une valeur source String
, mais elle ignore si elle provient d'un attribut @Column.name
ou si elle a été générée de manière implicite à partir du nom du champ.
Le ImprovedNamingStrategy
convertira CamelCase
en SNAKE_CASE
où, comme EJB3NamingStrategy
, il utilisera simplement le nom de la table sans modification.
Si vous ne souhaitez pas modifier la stratégie de dénomination, vous pouvez toujours spécifier votre nom de colonne en minuscule:
@Column(name="testname")
Il paraît que
@Column (name = "..")
est complètement ignoré sauf s'il y a
spring.jpa.hibernate.naming_strategy = org.hibernate.cfg.EJB3NamingStrategy
spécifié, donc pour moi c'est un bug.
J'ai passé quelques heures à essayer de comprendre pourquoi @Column (name = "..") était ignoré.
La stratégie par défaut pour @Column(name="TestName")
sera test_name
, il s'agit d'un comportement correct!
Si vous avez une colonne nommée TestName
dans votre base de données, vous devez changer l'annotation de colonne en @Column(name="testname")
.
Cela fonctionne parce que la base de données ne vous intéresse pas si vous nommez votre colonne NomTest ou nomTest (les noms de colonne ne sont pas sensibles à la casse !!).
Mais attention, il en va de même pour les noms de base de données et de table, qui sont sensibles à la casse sur les systèmes Unix mais sensibles à la casse sur les systèmes Windows (le fait que beaucoup de gens aient probablement veillé la nuit, travaillant sous Windows mais se déployant sous Linux :))
La seule solution qui a fonctionné pour moi était celle publiée par teteArg ci-dessus. Je suis sur Spring Boot 1.4.2 avec Hibernate 5. À savoir
spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
Pour plus d'informations, je publie la trace des appels de manière à indiquer clairement ce que Spring appelle dans Hibernate pour configurer la stratégie de dénomination.
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)
teteArg , merci beaucoup. Juste une information supplémentaire donc, tout le monde se cogner à cette question sera en mesure de comprendre pourquoi.
Ce que teteArg dit est indiqué dans les propriétés communes du démarrage initial: http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties .html
Apparemment, spring.jpa.hibernate.naming.strategy n'est pas une propriété prise en charge pour l'implémentation Spring JPA avec Hibernate 5.
Si vous souhaitez utiliser @Column (...), utilisez toujours des lettres minuscules, même si votre colonne de base de données est en camel.
Exemple: Si votre nom de colonne de base de données actuel est TestName
, utilisez:
@Column(name="testname") //all small-case
Si vous n'aimez pas cela, changez simplement le nom de colonne actuel de la base de données en: nom_test
Il s'avère que je dois juste convertir @column
nom testName en lettres minuscules, car il s'agissait initialement d'une casse de chameau.
Bien que je n’aie pas pu utiliser la réponse officielle, la question a été en mesure de m'aider à résoudre mon problème en me laissant savoir quoi enquêter.
Changement:
@Column(name="testName")
private String testName;
À:
@Column(name="testname")
private String testName;
Dans mon cas, l'annotation était sur la méthode getter () au lieu du champ lui-même (porté à partir d'une application héritée).
Spring ignore également l'annotation dans ce cas, mais ne se plaint pas. La solution consistait à le déplacer sur le terrain au lieu du getter.