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.