Spring Boot + JPA: ไม่สนใจคำอธิบายประกอบชื่อคอลัมน์


122

ฉันมีโปรแกรมฤดูใบไม้ผลิ Boot spring-boot-starter-data-jpaกับการพึ่งพา คลาสเอนทิตีของฉันมีคำอธิบายประกอบคอลัมน์ที่มีชื่อคอลัมน์ ตัวอย่างเช่น:

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

SQL ที่สร้างขึ้นโดยสร้างtest_nameเป็นชื่อคอลัมน์ หลังจากค้นหาวิธีแก้ปัญหาฉันพบว่าspring.jpa.hibernate.naming_strategy=org.hibernate.cfg.EJB3NamingStrategyแก้ไขปัญหาได้แล้ว (ชื่อคอลัมน์นำมาจากคำอธิบายประกอบคอลัมน์)

อย่างไรก็ตามคำถามของฉันคือเหตุใดโดยไม่ตั้งชื่อ _strategy เป็นEJB3NamingStrategyJPA จึงไม่สนใจคำอธิบายประกอบคอลัมน์ บางทีภาษาไฮเบอร์เนตอาจมีส่วนเกี่ยวข้องกับมัน? ฉันกำลังเชื่อมต่อกับ MS SQL 2014 Express และบันทึกของฉันประกอบด้วย:

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

1
คำถามนี้เป็นคำถามเกี่ยวกับชื่อคอลัมน์ที่จัดไว้ให้อย่างชัดเจนถูกเปลี่ยนแปลงมากกว่าละเว้น มันเดือดลงไปถึงการดำเนินการนี้แทนที่จะเป็นตัวแปรโปร่งใสที่คาดไว้ ไฮเบอร์เนตอาจละเว้น@Column(name="...")คำอธิบายประกอบตัวอย่างเช่นเมื่อคุณใช้ประเภทการเข้าถึงอื่นนอกเหนือจากที่คาดไว้ แต่นั่นไม่ใช่กรณีนี้
Vlastimil Ovčáčík

คำตอบ:


165

สำหรับ hibernate5 ฉันแก้ไขปัญหานี้โดยใส่บรรทัดถัดไปในไฟล์ 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 จำเป็นต้องใช้คุณสมบัตินี้เท่านั้นเพื่อคงชื่อไว้ตามที่เป็นอยู่
abhishek ringsia

1
ฉันมีปัญหาเดียวกันและการเพิ่มคุณสมบัติทั้ง 2 นั้นช่วยแก้ปัญหาให้ฉันได้ ฉันใช้ Spring Boot 1.4.3
Johan

1
นี่เป็นทางออกเดียวที่ใช้ได้ผลสำหรับฉันด้วย ฉันใช้ Spring Boot 1.4.2
Sanjiv Jivan

ฉันใช้ Spring Boot 1.5.9 ปล่อยโพสต์นี้เหมาะกับฉัน
IcyBrk

สุดยอด .. ฉันสงสัยว่าทำไมมันถึงไม่สนใจคำอธิบายประกอบ @Column ของฉัน ในที่สุดสิ่งนี้ก็ช่วยฉันได้ สำหรับฉันฉันรู้สึกว่านี่เป็นข้อบกพร่องหรือไม่มีฟังก์ชันการทำงาน
Raju Penumatsa

86

โดยค่าเริ่มต้น Spring ใช้org.springframework.boot.orm.jpa.SpringNamingStrategyเพื่อสร้างชื่อตาราง นี่คือส่วนขยายที่บางมากของorg.hibernate.cfg.ImprovedNamingStrategy. tableNameวิธีการในชั้นเรียนที่ผ่านมาStringค่า แต่ก็ไม่ทราบว่ามันมาจาก@Column.nameแอตทริบิวต์หรือถ้ามันได้รับการสร้างขึ้นโดยปริยายจากชื่อสนาม

ImprovedNamingStrategyจะแปลงCamelCaseการSNAKE_CASEที่เป็นEJB3NamingStrategyเพียงแค่ใช้ชื่อตารางไม่เปลี่ยนแปลง

หากคุณไม่ต้องการเปลี่ยนกลยุทธ์การตั้งชื่อคุณสามารถระบุชื่อคอลัมน์ของคุณเป็นตัวพิมพ์เล็กได้เสมอ:

@Column(name="testname")

1
สวัสดีฟิล โดยใช้สปริงบูตฉันได้เพิ่ม spring.jpa.hibernate.naming.strategy: org.hibernate.cfg.EJB3NamingStrategy แต่ดูเหมือนว่าจะไม่ได้ผลสำหรับฉัน คุณสามารถช่วยฉันได้ไหม?
BeeNoisy

ส่วนสำคัญของการตอบกลับคือการใส่ชื่อเป็นตัวพิมพ์เล็ก! ฉันไม่แนะนำให้เปลี่ยนสถานะ แต่การใส่ชื่อเป็นตัวพิมพ์เล็กเนื่องจากชื่อคอลัมน์ไม่คำนึงถึงตัวพิมพ์เล็กและใหญ่!
loicmathieu

31

ดูเหมือนว่า

@column (ชื่อ = "..")

ถูกละเว้นอย่างสมบูรณ์เว้นแต่จะมี

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

ระบุดังนั้นสำหรับฉันนี่คือข้อบกพร่อง

ฉันใช้เวลาสองสามชั่วโมงในการพยายามหาสาเหตุว่าทำไม @Column (name = ".. ") จึงถูกเพิกเฉย


4
ผมมีปัญหาเหมือนกัน. ฉันได้เพิ่มรายงานปัญหาที่นี่: github.com/spring-projects/spring-boot/issues/2129
Kacper86

ขอบคุณมาก. หายไปประมาณหนึ่งวันเพื่อชี้แอปของฉันไปยังฐานข้อมูลที่มีอยู่
Dmitry Erokhin

จริงๆแล้วไม่ได้ถูกละเลยเพียงแค่ใช้กลยุทธ์การตั้งชื่อสปริงเริ่มต้นกับแอตทริบิวต์ชื่อที่กำหนด อ่านคำตอบของ @PhilWebb
Michel Feldheim

16

กลยุทธ์เริ่มต้นสำหรับ@Column(name="TestName")จะเป็นtest_nameนี่คือพฤติกรรมที่ถูกต้อง!

ถ้าคุณมีคอลัมน์ที่มีชื่อในฐานข้อมูลของคุณคุณควรเปลี่ยนคำอธิบายประกอบคอลัมน์TestName@Column(name="testname")

ใช้งานได้เนื่องจากฐานข้อมูลไม่สนใจว่าคุณตั้งชื่อคอลัมน์ TestName หรือ testname ( ชื่อคอลัมน์ไม่คำนึงถึงตัวพิมพ์เล็กหรือใหญ่ !! )

แต่ระวังเหมือนกันใช้ไม่ได้กับชื่อฐานข้อมูลและชื่อตารางที่คำนึงถึงตัวพิมพ์เล็กและใหญ่ในระบบ Unix แต่เป็นกรณีที่มีความละเอียดอ่อนในระบบ Windows (ความจริงที่ว่าอาจทำให้ผู้คนจำนวนมากตื่นในเวลากลางคืนทำงานบน windows แต่ใช้งานบน linux :))


3
1. ที่จริงไม่เป็นความจริงชื่อคอลัมน์สามารถพิจารณาตัวพิมพ์เล็กและใหญ่ได้ขึ้นอยู่กับการกำหนดค่าของฐานข้อมูลที่คุณใช้ ... 2. @ ชื่อคอลัมน์ - ตามชื่อที่แนะนำควรเป็นที่สำหรับระบุชื่อคอลัมน์ฐานข้อมูลไม่ใช่ตัวระบุบางตัวที่เป็นกรอบ จะเปลี่ยนไประหว่างรันไทม์ ..
Kamil

1. ขอบคุณช่วยยกตัวอย่าง db ที่ชื่อคอลัมน์คำนึงถึงตัวพิมพ์เล็กและใหญ่โดยค่าเริ่มต้นได้ไหม 2. จริงๆแล้ว @Column ให้ชื่อตรรกะแก่เราที่แก้ไขเป็นชื่อจริงโดย PhysicalNamingStrategy อย่างน้อยก็น่าจะเป็นอย่างที่เอกสารกล่าว: docs.jboss.org/hibernate/orm/5.1/userguide/html_single/chapters/…
Orhan

2
1. ขอโทษที่ฉันทำไม่ได้เพราะฉันไม่สนใจว่าอันไหนมีมันตามค่าเริ่มต้นฉันสนใจว่า DBA จะตั้งค่าอะไรในการตั้งค่าที่ฉันใช้ 2. น่าเสียดายที่เป็นเรื่องจริง - เป็นเพียงความคิดเห็นส่วนตัวของฉันว่าแนวทางนี้ไม่ถูกต้องเนื่องจากบังคับให้ฉันคิดหรือเกี่ยวกับวิธีที่ชื่อจะถูกจับคู่กับคอลัมน์ในตอนท้ายหรือกลยุทธ์การตั้งชื่อที่จะใช้ซึ่งไม่ได้สัมผัสกับชื่อที่ระบุ
Kamil

1
จริงอยู่นั่นจะเป็นวิธีแก้ปัญหาที่ใช้งานง่ายที่สุดและแน่นอนว่าเอกสารที่ดีกว่านี้จะไม่เจ็บ
Orhan

ชื่อคอลัมน์ที่ตั้งไว้อย่างชัดเจนควรอยู่ภายใต้เงื่อนไขทั้งหมดแทนที่ชื่อที่สร้างขึ้นโดยปริยาย หากไม่เป็นเช่นนั้นนั่นเป็นข้อบกพร่องในการใช้งาน JPA
เข้ามาใน

13

ทางออกเดียวที่ใช้ได้ผลสำหรับฉันคือวิธีที่โพสต์โดย teteArg ด้านบน ฉันใช้ Spring Boot 1.4.2 w / Hibernate 5 คือ

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

สำหรับข้อมูลเชิงลึกเพิ่มเติมฉันโพสต์การติดตามการโทรเพื่อให้ชัดเจนว่า Spring เรียกอะไรใน Hibernate เพื่อตั้งค่ากลยุทธ์การตั้งชื่อ

      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ขอบคุณมาก เพียงแค่ข้อมูลเพิ่มเติมดังนั้นทุกคนที่เข้ามาในคำถามนี้จะเข้าใจได้ว่าทำไม

สิ่งที่teteArgกล่าวนั้นระบุไว้ในคุณสมบัติทั่วไปของ Spring Boot: http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html

เห็นได้ชัดว่าspring.jpa.hibernate.naming.strategyไม่ใช่คุณสมบัติที่รองรับสำหรับการใช้งาน Spring JPA โดยใช้ Hibernate 5


ฉันยินดีที่จะช่วยคุณ
teteArg

4

ปรากฎว่าฉันต้องแปลง @columnชื่อ testName เป็นตัวอักษรขนาดเล็กทั้งหมดเนื่องจากเป็นครั้งแรกในกรณีอูฐ

แม้ว่าฉันจะไม่สามารถใช้คำตอบอย่างเป็นทางการได้ แต่คำถามก็สามารถช่วยฉันแก้ปัญหาได้โดยแจ้งให้ฉันทราบว่าจะต้องตรวจสอบอะไร

เปลี่ยนแปลง:

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

ถึง:

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

3

หากคุณต้องการใช้ @Column (... ) ให้ใช้อักษรตัวพิมพ์เล็กเสมอแม้ว่าคอลัมน์ DB จริงของคุณจะอยู่ในตัวอักษรอูฐ

ตัวอย่าง: หากชื่อคอลัมน์ DB จริงของคุณTestNameใช้:

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

หากคุณไม่ชอบให้เปลี่ยนชื่อคอลัมน์ DB จริงเป็น: test_name


1

ในกรณีของฉันคำอธิบายประกอบอยู่ในเมธอด getter () แทนที่จะเป็นฟิลด์เอง (ย้ายมาจากแอปพลิเคชันเดิม)

Spring เพิกเฉยต่อคำอธิบายประกอบในกรณีนี้เช่นกัน แต่ไม่บ่น วิธีแก้ปัญหาคือย้ายไปที่สนามแทนที่จะเป็น getter


1
ขอบคุณสำหรับการอัพเดท. ข้อมูลที่มีค่าแน่นอน
เข้ามาใน

1

ฉันลองทำตามข้างต้นทั้งหมดแล้วก็ไม่ได้ผล สิ่งนี้ใช้ได้ผลสำหรับฉัน:

@Column(name="TestName")
public String getTestName(){//.........

ใส่คำอธิบายประกอบ getter แทนตัวแปร

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.