Spring Boot + JPA: Anotasi nama kolom diabaikan

121

Saya memiliki aplikasi Spring Boot dengan ketergantungan spring-boot-starter-data-jpa. Kelas entitas saya memiliki anotasi kolom dengan nama kolom. Sebagai contoh:

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

SQL yang dihasilkan oleh ini dibuat test_namesebagai nama kolom. Setelah mencari solusi, saya menemukan bahwa spring.jpa.hibernate.naming_strategy=org.hibernate.cfg.EJB3NamingStrategymemecahkan masalah (nama kolom diambil dari anotasi kolom).

Namun, pertanyaan saya adalah mengapa tanpa naming_strategy yang disetel ke EJB3NamingStrategyJPA mengabaikan anotasi kolom? Mungkin dialek hibernasi ada hubungannya dengan itu? Saya terhubung ke MS SQL 2014 Express dan log saya berisi:

Unknown Microsoft SQL Server major version [12] using SQL Server 2000 dialect
Using dialect: org.hibernate.dialect.SQLServerDialect 
Kamil
sumber
1
Pertanyaan ini adalah tentang nama kolom yang disediakan secara eksplisit diubah daripada diabaikan . Itu bermuara ini makhluk dieksekusi bukannya diharapkan varian transparan . Hibernate sebenarnya dapat mengabaikan @Column(name="...")anotasi, misalnya saat Anda menggunakan jenis akses selain yang diharapkan, tetapi tidak demikian di sini.
Vlastimil Ovčáčík

Jawaban:

163

Untuk hibernate5 saya memecahkan masalah ini dengan meletakkan baris berikutnya di file application.properties saya:

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
sumber
30
spring.jpa.hibernate.naming.physical-strategy = org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl, hanya properti ini yang diperlukan untuk mempertahankan nama apa adanya.
abhishek ringsia
1
Saya memiliki masalah yang sama dan menambahkan 2 properti tersebut menyelesaikannya untuk saya. Saya menjalankan Spring Boot 1.4.3
Johan
1
Ini adalah satu-satunya solusi yang berhasil untuk saya juga. Saya menggunakan Spring Boot 1.4.2
Sanjiv Jivan
Saya menggunakan Spring Boot 1.5.9. TOLONG, posting ini berfungsi untuk saya
IcyBrk
Luar biasa .. Saya bertanya-tanya mengapa anotasi @Column saya diabaikan. Akhirnya ini membantu saya. Bagi saya, saya merasa ini adalah bug atau fungsionalitas yang hilang.
Raju Penumatsa
86

Secara default Spring menggunakan org.springframework.boot.orm.jpa.SpringNamingStrategyuntuk menghasilkan nama tabel. Ini adalah ekstensi yang sangat tipis dari org.hibernate.cfg.ImprovedNamingStrategy. The tableNamemetode di kelas yang dilewatkan sumber Stringnilai tetapi tidak menyadari jika itu berasal dari @Column.nameatribut atau jika telah secara implisit dihasilkan dari nama field.

Ini ImprovedNamingStrategyakan dikonversi CamelCaseke SNAKE_CASEtempat yang EJB3NamingStrategyhanya menggunakan nama tabel yang tidak berubah.

Jika Anda tidak ingin mengubah strategi penamaan, Anda selalu dapat menentukan nama kolom Anda dalam huruf kecil:

@Column(name="testname")
Phil Webb
sumber
1
Hai, Phil. Dengan menggunakan spring boot, saya menambahkan spring.jpa.hibernate.naming.strategy: org.hibernate.cfg.EJB3NamingStrategy. Tapi sepertinya tidak berhasil untuk saya. Bisakah kamu membantuku?
BeeNoisy
Bagian penting dari tanggapan ini adalah menuliskan nama dalam huruf kecil! Saya menyarankan untuk tidak mengubah stategy tetapi untuk meletakkan nama dengan huruf kecil karena nama kolom tidak peka huruf besar kecil!
loicmathieu
31

Tampaknya

@Kolom (nama = "..")

sepenuhnya diabaikan kecuali jika ada

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

ditentukan, jadi bagi saya ini adalah bug.

Saya menghabiskan beberapa jam mencoba mencari tahu mengapa @Column (name = "..") diabaikan.

ncaralicea.dll
sumber
4
Saya memiliki masalah yang sama. Saya menambahkan laporan masalah di sini: github.com/spring-projects/spring-boot/issues/2129
Kacper86
Terima kasih banyak. Kehilangan sekitar satu hari untuk mengarahkan aplikasi saya ke db yang ada.
Dmitry Erokhin
Ini sebenarnya tidak diabaikan, hanya strategi penamaan pegas default yang diterapkan pada atribut nama yang diberikan. Baca jawaban @PhilWebb
Michel Feldheim
16

Strategi default untuk @Column(name="TestName")adalahtest_name , ini adalah perilaku yang benar!

Jika Anda memiliki kolom bernama TestNamedalam database Anda, Anda harus mengubah anotasi Kolom menjadi@Column(name="testname") .

Ini berfungsi karena database tidak peduli jika Anda menamai kolom Anda TestName atau testname ( nama kolom tidak peka huruf besar / kecil !! ).

Namun berhati-hatilah, hal yang sama tidak berlaku untuk nama database dan nama tabel, yang case-sensitive pada sistem Unix tetapi case-sensitive pada sistem Windows (fakta yang mungkin membuat banyak orang tetap terjaga di malam hari, bekerja di windows tetapi menggunakan di linux :))

Orhan
sumber
3
1. Sebenarnya itu tidak benar, nama kolom bisa menjadi case sensitive tergantung konfigurasi database yang Anda gunakan ... 2. @Column name - seperti yang disarankan nama harus menjadi tempat untuk memberikan nama kolom database, bukan beberapa pengenal yang merupakan framework akan berubah selama runtime ..
Kamil
1. Terima kasih, dapatkah Anda memberikan contoh db dengan nama kolom yang case sensitive secara default? 2. Sebenarnya @Column memberi kita nama logis yang diselesaikan menjadi nama fisik oleh PhysicalNamingStrategy, setidaknya seperti yang dikatakan oleh dokumen: docs.jboss.org/hibernate/orm/5.1/userguide/html_single/chapters/…
Orhan
2
1.Maaf, saya tidak bisa karena saya tidak peduli mana yang memilikinya secara default, saya peduli pengaturan apa yang ditetapkan oleh DBA pada yang saya gunakan. 2. Sayangnya itu benar - hanya pendapat pribadi saya bahwa pendekatan ini salah karena memaksa saya untuk berpikir atau tentang bagaimana nama akan dipetakan ke kolom di akhir, atau strategi penamaan mana yang digunakan yang tidak menyentuh nama yang diberikan.
Kamil
1
Benar, itu akan menjadi solusi yang paling intuitif, dan tentu saja dokumentasi yang lebih baik tentang ini tidak akan merugikan.
Orhan
nama kolom yang ditetapkan secara eksplisit harus dalam semua kondisi menimpa yang dibuat secara implisit. Jika tidak, itu adalah bug dalam implementasi JPA.
jwenting
13

Satu-satunya solusi yang berhasil untuk saya adalah solusi yang diposting oleh teteArg di atas. Saya menggunakan Spring Boot 1.4.2 w / Hibernate 5. Yaitu

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

Untuk wawasan tambahan, saya memposting jejak panggilan sehingga jelas apa yang membuat Spring menjadi Hibernate untuk mengatur strategi penamaan.

      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
sumber
6

teteArg , terima kasih banyak. Hanya informasi tambahan jadi, semua orang yang memiliki pertanyaan ini akan dapat memahami alasannya.

Apa yang teteArg katakan diindikasikan pada Spring Boot Common Properties: http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html

Rupanya, spring.jpa.hibernate.naming.strategy bukan properti yang didukung untuk implementasi JPA Musim Semi menggunakan Hibernate 5.

Romeo Jr Maranan
sumber
Saya senang membantu Anda
teteArg
4

Ternyata saya hanya harus pindah agama @column testName nama menjadi semua huruf kecil, karena awalnya menggunakan huruf unta.

Meskipun saya tidak dapat menggunakan jawaban resmi, pertanyaan tersebut dapat membantu saya memecahkan masalah saya dengan memberi tahu saya apa yang harus diselidiki.

Perubahan:

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

Untuk:

@Column(name="testname")
private String testName;
Mohammad Cali
sumber
3

Jika Anda ingin menggunakan @Column (...), gunakan selalu huruf kecil meskipun kolom DB Anda yang sebenarnya menggunakan huruf besar-kecil.

Contoh: Jika nama kolom DB Anda yang sebenarnya TestNamekemudian digunakan:

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

Jika Anda tidak menyukainya, cukup ubah nama kolom DB yang sebenarnya menjadi: test_name

Dekan
sumber
1

Dalam kasus saya, anotasi berada pada metode getter () dan bukan pada bidang itu sendiri (porting dari aplikasi warisan).

Spring mengabaikan anotasi dalam kasus ini juga, tetapi tidak mengeluh. Solusinya adalah dengan memindahkannya ke lapangan alih-alih pengambil.

java-addict301
sumber
1
terima kasih atas pembaruannya. Memang informasi yang sangat berharga.
jwenting