Ich habe eine einfache Spring-JPA-Konfiguration, in der ich Hibernates ImprovedNamingStrategy
konfiguriert habe. Das bedeutet, wenn meine Entitätsklasse eine Variable userName
enthält, sollte Hibernate diese zum Abfragen der Datenbank in user_name
Konvertieren. Diese Namenskonvertierung funktionierte jedoch nicht mehr, nachdem ich auf Hibernate 5 aktualisiert hatte. Ich erhalte den folgenden Fehler:
FEHLER: Unbekannte Spalte 'user0_.userName' in 'Feldliste'
Dies ist meine Hibernate-Konfiguration:
@Configuration
@EnableJpaRepositories("com.springJpa.repository")
@EnableTransactionManagement
public class DataConfig {
@Bean
public DataSource dataSource(){
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/test");
ds.setUsername("root");
ds.setPassword("admin");
return ds;
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(){
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setShowSql(Boolean.TRUE);
vendorAdapter.setDatabase(Database.MYSQL);
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendorAdapter);
factory.setDataSource(dataSource());
factory.setPackagesToScan("com.springJpa.entity");
Properties jpaProperties = new Properties();
jpaProperties.put("hibernate.ejb.naming_strategy","org.hibernate.cfg.ImprovedNamingStrategy");
jpaProperties.put("hibernate.dialect","org.hibernate.dialect.MySQL5InnoDBDialect");
factory.setJpaProperties(jpaProperties);
factory.afterPropertiesSet();
return factory;
}
@Bean
public SharedEntityManagerBean entityManager() {
SharedEntityManagerBean entityManager = new SharedEntityManagerBean();
entityManager.setEntityManagerFactory(entityManagerFactory().getObject());
return entityManager;
}
@Bean
public PlatformTransactionManager transactionManager() {
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(entityManagerFactory().getObject());
return txManager;
}
@Bean
public ImprovedNamingStrategy namingStrategy(){
return new ImprovedNamingStrategy();
}
}
Dies ist meine Entitätsklasse:
@Getter
@Setter
@Entity
@Table(name="user")
public class User{
@Id
@GeneratedValue
private Long id;
private String userName;
private String email;
private String password;
private String role;
}
Ich möchte meine Datenbankfelder nicht explizit innerhalb der @ Column-Annotationen benennen. Ich möchte eine Konfiguration, mit der Camel Case implizit in einen Unterstrich umgewandelt werden kann.
Bitte führen.
Vielen Dank für die Veröffentlichung Ihrer eigenen Lösung. Es hilft mir sehr, die Benennungsstrategie für Hibernate 5 festzulegen!
Die Eigenschaft hibernate.ejb.naming_strategy
Von Pre-Hibernate 5.0 scheint in zwei Teile aufgeteilt zu sein:
hibernate.physical_naming_strategy
hibernate.implicit_naming_strategy
Die Werte dieser Eigenschaften implementieren die Schnittstelle NamingStrategy
nicht wie hibernate.ejb.naming_strategy
. Für diese Zwecke gibt es zwei neue Schnittstellen:
org.hibernate.boot.model.naming.PhysicalNamingStrategy
org.hibernate.boot.model.naming.ImplicitNamingStrategy
Ruhezustand 5 bietet nur eine Implementierung von PhysicalNamingStrategy
(PhysicalNamingStrategyStandardImpl
), bei der angenommen wird, dass die Namen der physischen Bezeichner mit den logischen identisch sind.
Es gibt verschiedene Implementierungen von ImplicitNamingStrategy
, aber ich habe keine gefunden, die der alten ImprovedNamingStrategy
entspricht. (Siehe: org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyHbmImpl
)
Also habe ich mein eigenes PhysicalNamingStrategy
implementiert, was sehr einfach ist:
public class PhysicalNamingStrategyImpl extends PhysicalNamingStrategyStandardImpl implements Serializable {
public static final PhysicalNamingStrategyImpl INSTANCE = new PhysicalNamingStrategyImpl();
@Override
public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment context) {
return new Identifier(addUnderscores(name.getText()), name.isQuoted());
}
@Override
public Identifier toPhysicalColumnName(Identifier name, JdbcEnvironment context) {
return new Identifier(addUnderscores(name.getText()), name.isQuoted());
}
protected static String addUnderscores(String name) {
final StringBuilder buf = new StringBuilder( name.replace('.', '_') );
for (int i=1; i<buf.length()-1; i++) {
if (
Character.isLowerCase( buf.charAt(i-1) ) &&
Character.isUpperCase( buf.charAt(i) ) &&
Character.isLowerCase( buf.charAt(i+1) )
) {
buf.insert(i++, '_');
}
}
return buf.toString().toLowerCase(Locale.ROOT);
}
}
Beachten Sie, dass die addUnderscores()
-Methode aus dem Original org.hibernate.cfg.ImprovedNamingStrategy
Stammt.
Dann setze ich diese physikalische Strategie in die Datei persistence.xml:
<property name="hibernate.physical_naming_strategy" value="my.package.PhysicalNamingStrategyImpl" />
Es ist eine Falle, die Benennungsstrategie von Hibernate 5 als vorherige Versionseinstellungen festzulegen.
Danke und +1 an Samuel Andrés für die sehr hilfreiche Antwort, es ist jedoch wahrscheinlich eine gute Idee, die handgeschriebene Logik der Schlangenumhüllung zu umgehen. Hier ist die gleiche Lösung mit Guava.
Es wird davon ausgegangen, dass Ihre Entitätsnamen in StandardJavaClassFormat
und Spaltennamen in standardJavaFieldFormat
geschrieben sind.
Hoffentlich erspart dies einigen Leuten, die in Zukunft hierher kommen, etwas googeln :-)
import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import static com.google.common.base.CaseFormat.*;
public class SnakeCaseNamingStrategy extends PhysicalNamingStrategyStandardImpl {
public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment context) {
return new Identifier(
UPPER_CAMEL.to(LOWER_UNDERSCORE, name.getText()),
name.isQuoted()
);
}
public Identifier toPhysicalColumnName(Identifier name, JdbcEnvironment context) {
return new Identifier(
LOWER_CAMEL.to(LOWER_UNDERSCORE, name.getText()),
name.isQuoted()
);
}
}
danke für diesen Beitrag. Wenig ärgerlich, dass das Upgrade die Strategie für Tabellen- und Spaltennamen bricht. Anstatt die Logik aus ImprovedNamingStrategy
zu kopieren, können Sie auch die Delegierung verwenden.
public class TableNamingStrategy extends PhysicalNamingStrategyStandardImpl {
private static final String TABLE_PREFIX = "APP_";
private static final long serialVersionUID = 1L;
private static final ImprovedNamingStrategy STRATEGY_INSTANCE = new ImprovedNamingStrategy();
@Override
public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment context) {
return new Identifier(classToTableName(name.getText()), name.isQuoted());
}
@Override
public Identifier toPhysicalColumnName(Identifier name, JdbcEnvironment context) {
return new Identifier(STRATEGY_INSTANCE.classToTableName(name.getText()), name.isQuoted());
}
private String classToTableName(String className) {
return STRATEGY_INSTANCE.classToTableName(TABLE_PREFIX + className);
}
}
Bei jeder Antwort wird die Lösung durch die Implementierung von PhysicalNamingStrategy
veröffentlicht. Sie müssen jedoch nur ImplicitNamingStrategy
implementieren (und sollten dies auch tun).
Wenn eine Entität die Datenbanktabelle, der sie zugeordnet ist, nicht explizit benennt, müssen wir diesen Tabellennamen implizit bestimmen. Oder wenn ein bestimmtes Attribut die Datenbankspalte, der es zugeordnet ist, nicht explizit benennt, müssen wir diesen Spaltennamen implizit bestimmen. Es gibt Beispiele für die Rolle des Vertrags org.hibernate.boot.model.naming.ImplicitNamingStrategy, um einen logischen Namen zu ermitteln, wenn die Zuordnung keinen expliziten Namen enthielt.
Und der Code kann so einfach sein (unter Verwendung des ursprünglichen addUnderscores
wie in anderen Antworten):
public class ImplicitNamingStrategyImpl extends ImplicitNamingStrategyJpaCompliantImpl {
@Override
protected Identifier toIdentifier(String stringForm, MetadataBuildingContext buildingContext) {
return super.toIdentifier(addUnderscores(stringForm), buildingContext);
}
protected static String addUnderscores(String name) {
final StringBuilder buf = new StringBuilder(name.replace('.', '_'));
for (int i = 1; i < buf.length() - 1; i++) {
if (Character.isLowerCase(buf.charAt(i - 1))
&& Character.isUpperCase(buf.charAt(i))
&& Character.isLowerCase(buf.charAt(i + 1))) {
buf.insert(i++, '_');
}
}
return buf.toString().toLowerCase(Locale.ROOT);
}
}
hoffe das hilft:
hibernate.implicit_naming_strategy = .... ImplicitNamingStrategy hibernate.physical_naming_strategy = .... PhysicalNamingStrategyImpl
und hier ist der Code (der nur aus dem vorhandenen Code neu zusammengestellt wurde):
import Java.io.Serializable;
import Java.util.Locale;
import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
public class PhysicalNamingStrategyImpl extends PhysicalNamingStrategyStandardImpl implements Serializable {
public static final PhysicalNamingStrategyImpl INSTANCE = new PhysicalNamingStrategyImpl();
@Override
public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment context) {
return new Identifier(addUnderscores(name.getText()), name.isQuoted());
}
@Override
public Identifier toPhysicalColumnName(Identifier name, JdbcEnvironment context) {
return new Identifier(addUnderscores(name.getText()), name.isQuoted());
}
protected static String addUnderscores(String name) {
final StringBuilder buf = new StringBuilder( name.replace('.', '_') );
for (int i=1; i<buf.length()-1; i++) {
if (
Character.isLowerCase( buf.charAt(i-1) ) &&
Character.isUpperCase( buf.charAt(i) ) &&
Character.isLowerCase( buf.charAt(i+1) )
) {
buf.insert(i++, '_');
}
}
return buf.toString().toLowerCase(Locale.ROOT);
}
}
Keine Guaven- und Apachen-Utensilien
public class PhysicalNamingStrategyImpl extends PhysicalNamingStrategyStandardImpl {
public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment context) {
return context.getIdentifierHelper().toIdentifier(
name.getText().replaceAll("((?!^)[^_])([A-Z])", "$1_$2").toLowerCase(),
name.isQuoted()
);
}
public Identifier toPhysicalColumnName(Identifier name, JdbcEnvironment context) {
return context.getIdentifierHelper().toIdentifier(
name.getText().replaceAll("((?!^)[^_])([A-Z])", "$1_$2").toLowerCase(),
name.isQuoted()
);
}
}