2015-09-07 7 views
27

Ich habe eine einfache Spring-Jpa-Konfiguration, in der ich Hibernate ImprovedNamingStrategy konfiguriert habe. Das heißt, wenn meine Entitätsklasse eine Variable userName hat, sollte Hibernate sie in user_name für die Abfrage der Datenbank konvertieren. Aber diese Namensumwandlung aufgehört zu arbeiten, nachdem ich ein Upgrade 5. Hibernate Ich erhalte die Fehlermeldung:ImprovedNamingStrategy funktioniert nicht mehr in Hibernate 5

ERROR: Unknown column 'user0_.userName' in 'field list'

Dies ist meine Ruhe config:

@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(); 
    } 
} 

Das ist mein Entity-Klasse:

@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 ausdrücklich innerhalb der @ Column Annotationen benennen. Ich möchte meine Konfiguration, die Camel Case implizit in Unterstriche konvertieren kann.

Bitte führen.

+1

Ich verstehe nicht, warum Sie @Tyler nicht @Column –

+4

verwenden möchten, es ist nur für die Codierung einfache Hinzufügen „@Column“ für jede Variable nur ärgerlich ist, konfigurieren kann ich stattdessen Naming- Strategie, die den Namen der Variable zu db Spaltennamen zuordnen und ich kann vermeiden, so viele Spalte Annotation – Anup

Antwort

-8

Nur herausgefunden, das Problem, die Konfiguration ist absolut in Ordnung, wenn Sie eine Hibernate-Version < 5.0 verwenden, aber nicht für Hibernate> = 5.0.

Ich habe Hibernate 5.0.0.Final mit Spring 4.2.0.RELEASE verwendet. Ich denke, der Hibernate 5 ist nicht vollständig kompatibel mit Spring 4.2. Ich habe Hibernate einfach auf 4.2.1.Final herabgestuft und die Dinge haben gut funktioniert.

der Hibernate NamingStrategy Klasse wird in Hibernate veraltet 5.

50

Vielen Dank für Ihre eigene Lösung zu veröffentlichen. Es hilft mir so sehr, die Hibernate 5-Benennungsstrategie festzulegen!

Die hibernate.ejb.naming_strategy Eigenschaft von Pre-Hibernate 5.0 scheint in zwei Teile aufgeteilt:

  • hibernate.physical_naming_strategy
  • hibernate.implicit_naming_strategy

Die Werte dieser Eigenschaften nicht implementieren die NamingStrategy Schnittstelle als hibernate.ejb.naming_strategy tat. Es gibt zwei neue Schnittstellen für diese Zwecke:

  • org.hibernate.boot.model.naming.PhysicalNamingStrategy
  • org.hibernate.boot.model.naming.ImplicitNamingStrategy

Hibernate 5 stellt nur eine Implementierung von PhysicalNamingStrategy (PhysicalNamingStrategyStandardImpl), die physische Bezeichnernamen annimmt, sind die gleichen wie logische Einsen.

Es gibt mehrere Implementierungen von ImplicitNamingStrategy, aber ich fand keine Entsprechung zu der alten ImprovedNamingStrategy. (Siehe: org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyHbmImpl)

Also, ich meine eigene PhysicalNamingStrategy implementiert, die 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() Verfahren aus dem ursprünglichen org.hibernate.cfg.ImprovedNamingStrategy ist.

Dann stelle ich diese physische Strategie in die persistence.xml Datei:

<property name="hibernate.physical_naming_strategy" value="my.package.PhysicalNamingStrategyImpl" /> 

Es ist eine Falle Hibernate 5 Namensgebung Strategie als Vorversion Einstellungen einzustellen.

+1

Auch die Eigenschaft 'hibernate.implicit_naming_strategy' kann mit der benutzerdefinierten physikalischen Benennungsstrategie auf' org.hibernate.boot.model gesetzt werden .naming.ImplicitNamingStrategyLegacyHbmImpl' – Glenn

+0

Danke @Samuel für die Erklärung und ein Beispiel für die Implementierung einer eigenen Naming_Strategy. Es ist hilfreich und sogar ich bin auf der Suche nach ähnlichen Naming_Strategy – Anup

+0

Arbeitete für mich :) –

1

hoffe, das hilft:

hibernate.implicit_naming_strategy = .... ImplicitNamingStrategy hibernate.physical_naming_strategy = .... PhysicalNamingStrategyImpl

und hier ist der Code (nur von vorhandenen Code neu arrenged):

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); 
    } 

} 
2

Danke und +1 zu Samuel Andrés für die sehr hilfreiche Antwort, aber es ist wahrscheinlich eine gute Idee, die handgeschriebene Schlangen- zu vermeiden Gehäuselogik. Hier ist die gleiche Lösung mit Guava.

Es Ihre Entitätsnamen in den StandardJavaClassFormat und Spaltennamen in der Hoffentlich

standardJavaFieldFormat

geschrieben wird davon ausgegangen wird dies hier einige Leute sparen in Zukunft kommen einige 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() 
    ); 
    } 
} 
+0

Awesome, obwohl es einige seiner eigenen Schwächen hat.Der Standarddiskriminatorspaltenname von Hibernate lautet beispielsweise "DTYPE", der in "d_t_y_p_e" konvertiert wird. – xathien

+0

@xathien danke, war mir dessen nicht bewusst. Ich denke, ein statisches Mapping von Sonderfällen könnte hinzugefügt werden, um solche Dinge klar zu behandeln. – davnicwil

1

Dank für diesen Beitrag . Ein wenig nervig, dass das Upgrade die Tabellen- und Spaltennamen-Strategie durchbricht. Anstatt die Logik von ImprovedNamingStrategy zu kopieren, können Sie auch 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); 
    } 
} 
+0

Ich denke nicht, dass das eine clevere Idee ist. 'ImprovedNamingStrategy' implementiert eine veraltete Schnittstelle. Obwohl nur die Schnittstelle 'NamingStrategy' explizit als veraltet gekennzeichnet ist, würde ich annehmen, dass nach dem Entfernen alle implementierenden Klassen ebenfalls entfernt werden. –

+0

@ MarcelStör - Ich denke, das ist ein Merkmal dieses Ansatzes, kein Bug! Wenn und wenn Hibernate die alte "ImprovedNamingStrategy" ersetzt, werden sie hoffentlich die veraltete Klasse entfernen, und dieser Code bricht auf, und wir werden aufgefordert, zu der neuen offiziellen Implementierung zu wechseln und diese Problemumgehung zu entfernen. – Rich