Spring Boot + JPA: zignorowano adnotację nazwy kolumny

121

Mam aplikację Spring Boot z zależnościami spring-boot-starter-data-jpa. Moja klasa encji ma adnotację kolumny z nazwą kolumny. Na przykład:

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

Kod SQL wygenerowany przez to utworzony test_namejako nazwa kolumny. Po szukaniu rozwiązania stwierdziłem, że spring.jpa.hibernate.naming_strategy=org.hibernate.cfg.EJB3NamingStrategyproblem rozwiązał (nazwa kolumny jest pobierana z adnotacji kolumny).

Mimo to moje pytanie brzmi: dlaczego bez ustawienia naming_strategy na EJB3NamingStrategyJPA ignoruje adnotację kolumny? Może dialekt hibernacji ma z tym coś wspólnego? Łączę się z MS SQL 2014 Express i moje logi zawierają:

Unknown Microsoft SQL Server major version [12] using SQL Server 2000 dialect
Using dialect: org.hibernate.dialect.SQLServerDialect 
Kamil
źródło
1
To pytanie dotyczy zmiany, a nie ignorowania jawnie podanej nazwy kolumny . Sprowadza się to do wykonania tego zamiast oczekiwanego przezroczystego wariantu . Hibernate może faktycznie zignorować @Column(name="...")adnotacje, na przykład gdy używasz innego niż oczekiwany typu dostępu, ale tak nie jest w tym przypadku.
Vlastimil Ovčáčík

Odpowiedzi:

163

W przypadku hibernate5 problem rozwiązałem, umieszczając kolejne wiersze w moim pliku 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
źródło
30
spring.jpa.hibernate.naming.physical-strategy = org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl, tylko ta właściwość jest wymagana do zachowania nazwy bez zmian.
abhishek ringsia
1
Miałem ten sam problem i dodanie tych 2 właściwości rozwiązało go za mnie. Używam Spring Boot 1.4.3
Johan
1
To jedyne rozwiązanie, które też się sprawdziło. Używam Spring Boot 1.4.2
Sanjiv Jivan
Używam Spring Boot 1.5.9. RELEASE, ten post działa dla mnie
IcyBrk
Niesamowite ... Zastanawiałem się, dlaczego ignoruje moją adnotację @Column. Wreszcie mi to pomogło. Wydaje mi się, że to albo błąd, albo brakująca funkcjonalność.
Raju Penumatsa
86

Domyślnie Spring używa org.springframework.boot.orm.jpa.SpringNamingStrategydo generowania nazw tabel. To jest bardzo cienkie rozszerzenie org.hibernate.cfg.ImprovedNamingStrategy. Do tableNamemetody w tej klasie jest przekazywana Stringwartość źródłowa, ale nie wiadomo, czy pochodzi ona z @Column.nameatrybutu, czy też została niejawnie wygenerowana na podstawie nazwy pola.

ImprovedNamingStrategyPrzekształci CamelCasesię SNAKE_CASEgdzie jak EJB3NamingStrategytylko używa nazwy tabeli niezmienione.

Jeśli nie chcesz zmieniać strategii nazewnictwa, możesz zawsze podać nazwę kolumny małymi literami:

@Column(name="testname")
Phil Webb
źródło
1
Cześć, Phil. Używając rozruchu sprężynowego, dodałem spring.jpa.hibernate.naming.strategy: org.hibernate.cfg.EJB3NamingStrategy. Ale wygląda na to, że nie działa dla mnie. możesz mi pomóc?
BeeNoisy
Ważną częścią odpowiedzi jest wpisanie nazwy małymi literami! Radzę nie zmieniać strategii, ale wpisywać nazwę małymi literami, ponieważ w nazwach kolumn wielkość liter nie jest rozróżniana!
loicmathieu
31

Wygląda na to że

@Kolumna (nazwa = "..")

jest całkowicie ignorowany, chyba że istnieje

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

określony, więc dla mnie jest to błąd.

Spędziłem kilka godzin, próbując dowiedzieć się, dlaczego @Column (name = "..") został zignorowany.

ncaralicea
źródło
4
Miałem ten sam problem. Dodałem zgłoszenie problemu tutaj: github.com/spring-projects/spring-boot/issues/2129
Kacper86
Wielkie dzięki. Straciłem około jednego dnia, aby skierować moją aplikację do istniejącej bazy danych.
Dmitry Erokhin
W rzeczywistości nie jest ignorowany, tylko domyślna strategia nazewnictwa sprężyn jest stosowana do danego atrybutu nazwy. Przeczytaj odpowiedź @PhilWebb
Michel Feldheim
16

Domyślną strategią dla @Column(name="TestName")will test_namejest prawidłowe zachowanie!

Jeśli masz kolumnę o nazwie TestNamew swojej bazie danych, powinieneś zmienić Adnotację kolumny na @Column(name="testname").

To działa, ponieważ baza danych nie dba o to, czy nazwiesz swoją kolumnę TestName czy testname (w nazwach kolumn nie jest rozróżniana wielkość liter !! ).

Ale uwaga, to samo nie dotyczy nazw baz danych i nazw tabel, które uwzględniają wielkość liter w systemach uniksowych, ale wielkość liter w systemach Windows (fakt, że prawdopodobnie wiele osób nie spało w nocy, pracując w systemie Windows, ale wdrażając na Linuksie :))

Orhan
źródło
3
1. Właściwie to nieprawda, w nazwach kolumn może być rozróżniana wielkość liter w zależności od konfiguracji używanej bazy danych ... 2. @ Nazwa kolumny - jak sugeruje nazwa, powinno być miejscem na podanie nazwy kolumny bazy danych, a nie jakiegoś identyfikatora, który zmieni się w trakcie działania ..
Kamil
1. Dzięki, czy możesz podać przykład bazy danych, w której nazwy kolumn są domyślnie uwzględniane wielkości liter? 2. Właściwie @Column podaje nam logiczne nazwy, które są tłumaczone na nazwy fizyczne przez PhysicalNamingStrategy, przynajmniej wydaje się, że tak mówi dokument: docs.jboss.org/hibernate/orm/5.1/userguide/html_single/chapters/ ...
Orhan
2
Przepraszam, nie mogę, ponieważ nie obchodzi mnie, który ma to domyślnie, obchodzi mnie, jakie ustawienia są ustawione przez DBA na tym, którego używam. 2. To niestety prawda - to tylko moja osobista opinia, że ​​to podejście jest błędne, ponieważ zmusza mnie do myślenia lub o tym, jak nazwa zostanie odwzorowana na kolumnę na końcu, lub jaką strategię nazewnictwa użyć, która nie ma wpływu na podane nazwy.
Kamil
1
To prawda, byłoby to najbardziej intuicyjne rozwiązanie i oczywiście lepsza dokumentacja na ten temat nie zaszkodzi.
Orhan
jawnie ustawiona nazwa kolumny powinna we wszystkich warunkach przesłonić niejawnie wygenerowaną. Jeśli tak nie jest, jest to błąd w implementacji JPA.
jwenting
13

Jedynym rozwiązaniem, które zadziałało, było to opublikowane przez teteArg powyżej. Jestem na Spring Boot 1.4.2 z Hibernate 5. Mianowicie

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

Aby uzyskać dodatkowy wgląd, publikuję śledzenie połączeń, aby było jasne, co wywołuje Spring w Hibernate, aby skonfigurować strategię nazewnictwa.

      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
źródło
6

teteArg , bardzo dziękuję. Tylko dodatkowa informacja, więc każdy, kto wpadnie na to pytanie, będzie mógł zrozumieć, dlaczego.

To, co powiedział teteArg , jest wskazane we wspólnych właściwościach Spring Boot: http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html

Najwyraźniej spring.jpa.hibernate.naming.strategy nie jest obsługiwaną właściwością dla implementacji Spring JPA przy użyciu Hibernate 5.

Romeo Jr Maranan
źródło
Chętnie
4

Okazuje się, że muszę po prostu przekonwertować @columnnazwę testName na wszystkie małe litery, ponieważ początkowo było to w przypadku wielbłąda.

Chociaż nie byłem w stanie skorzystać z oficjalnej odpowiedzi, pytanie pomogło mi rozwiązać problem, dając mi znać, co mam zbadać.

Zmiana:

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

Do:

@Column(name="testname")
private String testName;
Mohammad Cali
źródło
3

Jeśli chcesz używać @Column (...), używaj zawsze małych liter, nawet jeśli twoja rzeczywista kolumna DB jest w wielbłądzie.

Przykład: jeśli rzeczywista nazwa kolumny bazy danych to TestName:

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

Jeśli ci się to nie podoba, po prostu zmień rzeczywistą nazwę kolumny DB na: nazwa_testu

Dziekan
źródło
1

W moim przypadku adnotacja znajdowała się w metodzie getter () zamiast w samym polu (przeniesionym ze starszej aplikacji).

Wiosna również w tym przypadku ignoruje adnotację, ale nie narzeka. Rozwiązaniem było przeniesienie go na pole zamiast do gettera.

java-addict301
źródło
1
Dziękuję za aktualizację. Rzeczywiście cenne informacje.
jwenting