Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hibernate naming strategy per entity

I have one global naming strategy but for a few entities I want to use a different one. Is it possible in jpa or hibernate?

clarification: i don't want to use @Table(name="xxx") nor @Column(name="xxx"). i'm asking about naming strategy component (described for example here: Hibernate naming strategy). that's a component that infer the column and table names for you

like image 880
piotrek Avatar asked Mar 25 '14 15:03

piotrek


People also ask

How to change Hibernate naming strategy?

This name can be customized in two ways: it can be derived automatically by using an ImplicitNamingStrategy or it can be defined explicitly by using annotations. The ImplicitNamingStrategy governs how Hibernate derives a logical name from our Java class and property names.

What is the default naming strategy Hibernate?

By default, Hibernate uses the implicit naming strategy defined by the JPA specification. This value is an alias for jpa. This is the naming strategy defined by the JPA 2.0 specification. The logical name of an entity class is either the name provided in the @Entity annotation or the unqualified class name.

What is Spring jpa Hibernate naming strategy?

naming. strategy ; Hibernate 5 defines a Physical and Implicit naming strategies. Spring Boot configures SpringPhysicalNamingStrategy by default. This implementation provides the same table structure as Hibernate 4: all dots are replaced by underscores and camel cases are replaced by underscores as well.

What is PhysicalNamingStrategy?

PhysicalNamingStrategy. The idea of a PhysicalNamingStrategy is to define custom naming rules without having to hard-code them into the mapping via explicit names. Following is an implementation of PhysicalNamingStrategy to define custom table name and column name.


1 Answers

I don't see a way in the Hibernate source code. The EntityBinder is coming up with names using ObjectNameNormalizer.NamingStrategyHelper, which gets the naming strategy from either Configuration.namingStrategy (the global one) or from a complex path which goes through MetadataImpl and lands nowhere (no usages).

So you're likely stuck with overriding field names manually. I don't even see an obvious way to get context about the field, so I think even a split-brain naming strategy looks like it's out of the question.

Update: After seeing @anthony-accioly's answer, I thought I that last sentence may have been wrong. So I tested it as follows

package internal.sandbox.domain;

@Entity
public class SomeEntity {

    private String id;
    private String someField;

    @Id
    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getSomeField() {
        return someField;
    }

    public void setSomeField(String someField) {
        this.someField = someField;
    }
}

with a JpaConfiguration as follows

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories("internal.sandbox.dao")
@Import(DataSourceConfiguration.class)
public class JpaConfiguration {

    @Bean
    @Autowired
    public LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBean(DataSource dataSource) {

        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        vendorAdapter.setDatabasePlatform("org.hibernate.dialect.PostgreSQL82Dialect");
        vendorAdapter.setDatabase(Database.POSTGRESQL);

        LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
        factory.setJpaVendorAdapter(vendorAdapter);
        factory.setPackagesToScan("internal.sandbox"); // note, no ".domain"
        factory.setDataSource(dataSource);

        Properties properties = new Properties();
        properties.setProperty("hibernate.cache.use_second_level_cache", "false");
        properties.setProperty("hibernate.ejb.naming_strategy", "org.hibernate.cfg.ImprovedNamingStrategy");

        factory.setJpaProperties(properties);

        return factory;
    }
    ...

a Spring Data DAO as follows

public interface SomeEntityDao extends CrudRepository<SomeEntity, String> {
}

and an integration test as follows

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {ApplicationConfiguration.class, JpaConfiguration.class})
public class SomeEntityDaoIntegrationTests {

    @Autowired
    private SomeEntityDao someEntityDao;

    @Test
    public void testSave() {

        SomeEntity someEntity = new SomeEntity();
        someEntity.setId("foo");
        someEntity.setSomeField("bar");

        this.someEntityDao.save(someEntity);
    }
}

I put breakpoints in the ImprovedNamingStrategy, and classToTableName() was called with "SomeEntity" and propertyToColumnName() was called with "someField".

In other words, package information isn't being passed in, so at least in this setup, it can't be used to apply a different naming strategy based on package name.

like image 200
Emerson Farrugia Avatar answered Oct 20 '22 19:10

Emerson Farrugia