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 

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

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")

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.


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 :))


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)

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.



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;

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


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.


1
Dziękuję za aktualizację. Rzeczywiście cenne informacje.
jwenting
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.