Spring Boot + JPA: anotação do nome da coluna ignorada


121

Eu tenho um aplicativo Spring Boot com dependência spring-boot-starter-data-jpa. Minha classe de entidade possui uma anotação de coluna com um nome de coluna. Por exemplo:

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

SQL gerado por isso criado test_namecomo o nome das colunas. Depois de procurar uma solução, descobri que spring.jpa.hibernate.naming_strategy=org.hibernate.cfg.EJB3NamingStrategyresolveu o problema (o nome da coluna é obtido da anotação da coluna).

Ainda assim, minha pergunta é por que, sem naming_strategy definido como EJB3NamingStrategyJPA, está ignorando a anotação da coluna? Talvez o dialeto de hibernação tenha algo a ver com isso? Estou conectando ao MS SQL 2014 Express e meus logs contêm:

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

1
Esta pergunta é sobre o nome da coluna explicitamente fornecido sendo alterado em vez de ignorado . Tudo se resume a isso sendo executado em vez da variante transparente esperada . O Hibernate pode realmente ignorar @Column(name="...")anotações, por exemplo, quando você usa outro tipo de acesso que não o esperado, mas esse não é o caso aqui.
Vlastimil Ovčáčík 28/01

Respostas:


163

Para o hibernate5, resolvi esse problema colocando as próximas linhas no meu arquivo 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, apenas essa propriedade é necessária para manter o nome como está.
Abhishek ringsia

1
Eu tive o mesmo problema e a adição dessas 2 propriedades resolveu o problema para mim. Estou executando o Spring Boot 1.4.3
Johan

1
Esta é a única solução que funcionou para mim também. Estou usando o Spring Boot 1.4.2
Sanjiv Jivan

Eu estou usando Spring Bota 1.5.9.RELEASE, este post funciona para mim
IcyBrk

Impressionante .. Fiquei me perguntando por que estava ignorando minha anotação @Column. Finalmente, isso me ajudou. Para mim, sinto que isso é um bug ou falta de funcionalidade.
Raju Penumatsa 13/07/19

86

Por padrão, o Spring usa org.springframework.boot.orm.jpa.SpringNamingStrategypara gerar nomes de tabelas. Esta é uma extensão muito fina de org.hibernate.cfg.ImprovedNamingStrategy. O tableNamemétodo nessa classe recebe um Stringvalor de origem, mas não se sabe se é proveniente de um @Column.nameatributo ou se foi gerado implicitamente a partir do nome do campo.

O ImprovedNamingStrategyirá converter CamelCasepara SNAKE_CASEonde como o EJB3NamingStrategyjust usa o nome da tabela inalterado.

Se você não quiser alterar a estratégia de nomenclatura, poderá sempre especificar o nome da coluna em minúsculas:

@Column(name="testname")

1
Olá Phil. Usando o boot de primavera, adicionei spring.jpa.hibernate.naming.strategy: org.hibernate.cfg.EJB3NamingStrategy. Mas parece que não funciona para mim. pode me ajudar?
precisa saber é o seguinte

A parte importante da resposta é colocar o nome em letras minúsculas! Aconselho a não alterar a estratégia, mas colocar o nome em minúsculas, pois o nome da coluna não faz distinção entre maiúsculas e minúsculas!
Loicmathieu

31

Parece que

@Column (nome = "..")

é completamente ignorado, a menos que haja

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

especificado, então para mim isso é um bug.

Passei algumas horas tentando descobrir por que @Column (name = "..") foi ignorado.


4
Eu tive o mesmo problema. Eu adicionei um relatório de problema aqui: github.com/spring-projects/spring-boot/issues/2129 #
Kacper86

Muito obrigado. Perdi cerca de um dia para apontar meu aplicativo para o banco de dados existente.
Dmitry Erokhin

Na verdade, não é ignorado, apenas a estratégia de nomeação padrão da primavera é aplicada no atributo de nome fornecido. Leia a resposta @PhilWebb
Michel Feldheim

15

A estratégia padrão para @Column(name="TestName")será test_name, este é o comportamento correto!

Se você tiver uma coluna nomeada TestNameem seu banco de dados, altere a anotação de Coluna para @Column(name="testname").

Isso funciona porque o banco de dados não se importa se você nomear sua coluna TestName ou testname (os nomes das colunas não diferenciam maiúsculas de minúsculas !! ).

Mas cuidado, o mesmo não se aplica aos nomes de bancos de dados e tabelas, que diferenciam maiúsculas de minúsculas nos sistemas Unix, mas diferenciam maiúsculas de minúsculas nos sistemas Windows (o fato de que provavelmente manteve muitas pessoas acordadas à noite, trabalhando no Windows, mas implantando no Linux :))


3
1. Na verdade, isso não é verdade, os nomes das colunas podem fazer distinção entre maiúsculas e minúsculas, dependendo da configuração do banco de dados que você está usando ... 2. @Column name - como o nome sugere, deve ser um local para fornecer o nome da coluna do banco de dados, não um identificador que seja uma estrutura vai mudar durante a execução ..
Kamil

1. Obrigado, você pode dar um exemplo de db em que os nomes das colunas diferenciam maiúsculas de minúsculas por padrão? 2. Na verdade, o @Column nos fornece nomes lógicos que são resolvidos para nomes físicos pelo PhysicalNamingStrategy, pelo menos parece o que o documento diz: docs.jboss.org/hibernate/orm/5.1/userguide/html_single/chapters/…
Orhan

2
1.Desculpe, não posso, pois não me importo com qual deles o possui por padrão, me importo com as configurações definidas pelo DBA na que estou usando. 2. Infelizmente, isso é verdade - é apenas minha opinião pessoal de que essa abordagem está errada, pois me força a pensar ou sobre como o nome seria mapeado para a coluna no final ou qual estratégia de nomeação usar e que não toca nos nomes fornecidos.
21917 Kamil

1
É verdade que essa seria a solução mais intuitiva e, é claro, uma documentação melhor sobre isso não faria mal.
Orhan 29/06

um nome de coluna definido explicitamente deve sob todas as condições substituir um gerado implicitamente. Caso contrário, isso é um bug na implementação da JPA.
jwenting

13

A única solução que funcionou para mim foi a postada pelo teteArg acima. Estou no Spring Boot 1.4.2 com Hibernate 5. Ou seja

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 informações adicionais, eu estou postando o rastreamento de chamadas, para que fique claro o que as chamadas da Spring estão fazendo no Hibernate para configurar a estratégia de nomeação.

      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 , muito obrigado. Apenas uma informação adicional, para que todos que se deparem com essa pergunta possam entender o porquê.

O que o teteArg disse está indicado nas Propriedades comuns da inicialização do Spring: http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html

Aparentemente, spring.jpa.hibernate.naming.strategy não é uma propriedade suportada para a implementação da JPA do Spring usando o Hibernate 5.


Estou feliz em ajudá-lo
teteArg

4

Acontece que eu só tenho que converter o @columnnome testName em todas as letras minúsculas, já que foi inicialmente em caixa de camelo.

Embora eu não tenha conseguido usar a resposta oficial, a pergunta foi capaz de me ajudar a resolver meu problema, informando o que investigar.

Mudança:

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

Para:

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

3

Se você deseja usar @Column (...), use letras minúsculas sempre que sua coluna de banco de dados real esteja em caixa de camelo.

Exemplo: se o nome real da coluna do banco de dados for TestName, use:

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

Se você não gostar disso, basta alterar o nome da coluna do banco de dados real para: test_name


1

No meu caso, a anotação estava no método getter () em vez do próprio campo (portado de um aplicativo herdado).

O Spring também ignora a anotação neste caso, mas não reclama. A solução foi movê-lo para o campo em vez do getter.


1
obrigado pela atualização. Informações valiosas de fato.
jwenting
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.