web-dev-qa-db-fra.com

Spring - Configuration de la stratégie de nommage d'Hibernate 5

J'écris une application en utilisant la base de données postgresql et les frameworks Spring + hibernate.

J'ai mis à jour le framework Spring de la version 4.1.5.RELEASE à la version 4.2.0.RELEASE et mis à niveau le framework hibernate de la version 4.3.7.Final à la version 5.0.0.Final.

Après la mise à niveau, j'ai des problèmes avec NamingStrategy. Dans la base de données postgresql, les noms des colonnes de table sont en minuscules séparés par un trait de soulignement, dans la couche application, les propriétés du bean sont en camelcase.

Cela fonctionne fichier de configuration de printemps pour une version plus ancienne:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd">

    <context:component-scan base-package="fms" />

    <bean id="microFmsDataSource" class="org.Apache.Tomcat.jdbc.pool.DataSource" destroy-method="close">
        <property name="driverClassName" value="org.postgresql.Driver" />
        <property name="url" value="***" />
        <property name="username" value="***" />
        <property name="password" value="***" />

        <property name="testOnBorrow" value="true" />
        <property name="testOnReturn" value="true" />
        <property name="testWhileIdle" value="true" />
        <property name="validationQuery" value="select 1" />
        <property name="initialSize" value="5" />
        <property name="minIdle" value="10" />
        <property name="maxIdle" value="100" />
        <property name="maxActive" value="100" />
        <property name="removeAbandoned" value="true" />
    </bean>

    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="microFmsDataSource"/>

        <property name="packagesToScan">
            <list>
                <value>fms</value>
            </list>
        </property>

        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
        </property>

        <property name="jpaPropertyMap">
            <map>
                <entry key="hibernate.cache.provider_class" value="org.hibernate.cache.NoCacheProvider" />
                <entry key="hibernate.hbm2ddl.auto" value="validate" />
                <entry key="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" />
                <entry key="hibernate.show_sql" value="true" />
                <entry key="hibernate.format_sql" value="true" />
                <entry key="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy" />
            </map>
        </property>
    </bean>

    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>

    <tx:annotation-driven transaction-manager="transactionManager"/>
</beans>

Après la mise à niveau, j'ai changé la configuration de NamingStrategy:

<entry key="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy" />

comme ça:

<entry key="hibernate.implicit_naming_strategy" value="***" />

et essayé toutes les variantes d'options répertoriées dans hibernate javadoc: https://docs.jboss.org/hibernate/orm/5.0/javadocs/org/hibernate/cfg/AvailableSettings.html#IMPLICIT_NAMING_STRATEGY

mais sans succès.

Pouvez-vous me dire quelle est l'alternative de ImprovedNamingStrategy dans Hibernate 5 et fournir un exemple de configuration de travail?

25
Yoh0xFF

Je pense avoir trouvé la solution.

Pour atteindre mon objectif, j'ai utilisé hibernate.physical_naming_strategy configuration, au lieu de hibernate.implicit_naming_strategy.

J'ai créé une implémentation de l'interface PhysicalNamingStrategy qui simule une partie des fonctionnalités de la classe ImprovedNamingStrategy d'origine:

package fms.util.hibernate;

import org.Apache.commons.lang.StringUtils;
import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.boot.model.naming.PhysicalNamingStrategy;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;

public class ImprovedNamingStrategy implements PhysicalNamingStrategy {

    @Override
    public Identifier toPhysicalCatalogName(Identifier identifier, JdbcEnvironment jdbcEnv) {
        return convert(identifier);
    }

    @Override
    public Identifier toPhysicalColumnName(Identifier identifier, JdbcEnvironment jdbcEnv) {
        return convert(identifier);
    }

    @Override
    public Identifier toPhysicalSchemaName(Identifier identifier, JdbcEnvironment jdbcEnv) {
        return convert(identifier);
    }

    @Override
    public Identifier toPhysicalSequenceName(Identifier identifier, JdbcEnvironment jdbcEnv) {
        return convert(identifier);
    }

    @Override
    public Identifier toPhysicalTableName(Identifier identifier, JdbcEnvironment jdbcEnv) {
        return convert(identifier);
    }

    private Identifier convert(Identifier identifier) {
        if (identifier == null || StringUtils.isBlank(identifier.getText())) {
            return identifier;
        }

        String regex = "([a-z])([A-Z])";
        String replacement = "$1_$2";
        String newName = identifier.getText().replaceAll(regex, replacement).toLowerCase();
        return Identifier.toIdentifier(newName);
    }
}

Après avoir créé cette classe, j'ai changé ma configuration de:

<entry key="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy" />

pour ça:

<entry key="hibernate.physical_naming_strategy" value="fms.util.hibernate.ImprovedNamingStrategy" />

et maintenant tout fonctionne correctement.

Cette solution ne couvre qu'une petite partie de ImprovedNamingStrategy. Dans mon projet, pour le mappage de table et le mappage de jointure, je spécifie toujours explicitement le nom de la table ou de la colonne de jointure. Je m'appuie sur la conversion de nom implicite uniquement pour les noms de colonne. Cette solution simple était donc acceptable pour moi.

Voici un exemple complet de mon fichier de configuration Spring:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd">

    <context:component-scan base-package="fms" />

    <bean id="microFmsDataSource" class="org.Apache.Tomcat.jdbc.pool.DataSource" destroy-method="close">
        <property name="driverClassName" value="org.postgresql.Driver" />
        <property name="url" value="***" />
        <property name="username" value="***" />
        <property name="password" value="***" />

        <property name="testOnBorrow" value="true" />
        <property name="testOnReturn" value="true" />
        <property name="testWhileIdle" value="true" />
        <property name="validationQuery" value="select 1" />
        <property name="initialSize" value="5" />
        <property name="minIdle" value="10" />
        <property name="maxIdle" value="100" />
        <property name="maxActive" value="100" />
        <property name="removeAbandoned" value="true" />
    </bean>

    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="microFmsDataSource"/>

        <property name="packagesToScan">
            <list>
                <value>fms</value>
            </list>
        </property>

        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
        </property>

        <property name="jpaPropertyMap">
            <map>
                <entry key="hibernate.cache.provider_class" value="org.hibernate.cache.NoCacheProvider" />
                <entry key="hibernate.hbm2ddl.auto" value="validate" />
                <entry key="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" />
                <entry key="hibernate.show_sql" value="true" />
                <entry key="hibernate.format_sql" value="true" />
                <entry key="hibernate.physical_naming_strategy" value="fms.util.hibernate.ImprovedNamingStrategy" />
            </map>
        </property>
    </bean>

    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>

    <tx:annotation-driven transaction-manager="transactionManager"/>
</beans>

J'espère que cette solution sera utile à quelqu'un. :)

29
Yoh0xFF

Ce travail pour moi, de http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/orm/hibernate5/LocalSessionFactoryBean.html

<bean id="sessionFactory" 
    class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">

    <!-- convert aaBb to aa_bb -->
    <property name="PhysicalNamingStrategy">
        <bean class="fms.util.hibernate.ImprovedNamingStrategy" />
    </property>

    <!-- convert aa_bb to aaBb -->
    <property name="ImplicitNamingStrategy">
        <bean class="org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyHbmImpl" />
    </property>
...
</bean>   
5
Daniel Qian

J'ai eu exactement le même problème. Je l'ai corrigé avec l'implémentation par défaut de Spring Boot:

<property name="hibernate.implicit_naming_strategy" value="org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy" />
<property name="hibernate.physical_naming_strategy" value="org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy" />
4
JSimo

Pour tous ceux qui recherchent une solution de configuration Java Java

Le hibernate.ejb.naming_strategy la propriété semble divisée en deux parties dans hibernate 5.X:

hibernate.physical_naming_strategy

hibernate.implicit_naming_strategy

Spring fournit SpringImplicitNamingStrategy et SpringPhysicalNamingStrategy à cet effet.

Voici mon approche:

import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy;
import org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
@DependsOn("myDataSource")
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef = "myEntityManagerFactory",
        basePackages={"com.myapp.repo"},
        transactionManagerRef="myTransactionManager"
        )
public class MyJpaConfig {

    private Map<String, Object> properties;

    public MyJpaConfig() {
        properties = new HashMap<>();
        properties.put("hibernate.implicit_naming_strategy", SpringImplicitNamingStrategy.class.getName());
        properties.put("hibernate.physical_naming_strategy", SpringPhysicalNamingStrategy.class.getName());

    }

    @Bean(name = "myEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder builder,
            @Qualifier("systemDataSource") DataSource dataSource) {
        LocalContainerEntityManagerFactoryBean build = builder.dataSource(dataSource)
                .packages("com.myapp.entity")
                .properties(properties)
                .build();
        return build;

    }

    @Bean(name = "myTransactionManager")
    public PlatformTransactionManager myTransactionManager(
            @Qualifier("myEntityManagerFactory") EntityManagerFactory myEntityManagerFactory) {
        return new JpaTransactionManager(myEntityManagerFactory);
    }
}
4
Manish Kothari

essaye ça:

@Bean
public LocalSessionFactoryBean getSessionFactory() {
    LocalSessionFactoryBean localSessionFactoryBean = new LocalSessionFactoryBean();
    localSessionFactoryBean.setDataSource(getDataSource());
    localSessionFactoryBean.setHibernateProperties(getHibernateProperties());
    localSessionFactoryBean.setPackagesToScan(new String[]{"com.xxx.pojo"});
    // -----important-----
    localSessionFactoryBean.setPhysicalNamingStrategy(new CustomNamingStrategy());
    return localSessionFactoryBean;
}

public class CustomNamingStrategy extends PhysicalNamingStrategyStandardImpl {***
0
helloworld1970

Veuillez trouver ci-dessous 3 points que j'ai découverts en travaillant sur la stratégie de nommage:

  1. Si vous fournissez des annotations @Table Et @Column Dans vos classes d'entité avec des noms fournis avec un trait de soulignement, c'est-à-dire ser_id ie @Column(name="user_id"), cela prendra la nom de colonne comme ser_id; si vous le donnez comme serid alors il changera en ser_id si vous n'utilisez aucune stratégie ou stratégie implicite (spécifiquement org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyHbmImpl). Donc, si vous voulez une stratégie où le nom d'attribut d'entité change en un avec un soulignement et des lettres minuscules, c'est-à-dire quelque chose de serId à ser_id, vous devez utiliser une stratégie implicite ou aucune (qui utilise en fait une stratégie implicite).

  2. Si vous ne voulez pas que votre stratégie de nommage ajoute un trait de soulignement au nom de la colonne ou au nom de classe, alors la stratégie que vous devez utiliser devrait ressembler à: spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl. Les éléments que vous fournissez dans les annotations @Table Et @Column’s Attribut de nom resteront tels quels.

  3. Si vous ne souhaitez pas fournir d'annotations et souhaitez gérer manuellement le nom de la table et les noms des colonnes, vous devez étendre la classe org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl Et remplacer les méthodes requises. Si vous utilisez toujours des annotations pour certains cas ici, n'oubliez pas que les méthodes remplacées s'appliqueront aux noms écrits dans ces annotations.

0
Raj Kundalia