Spring Boot Hibernate 5 Ignoring @Table and @Column
Asked Answered
W

2

14

This is driving me mad.

I'm implementing Spring Social and it requires you to have a database table named UserConnection (instead of using the standard naming convention of using an underscore to separate the two words).

So in my naive world view, I assumed it would be easily solved by specifying @Table(name="UserConnection")... but no, that would be all too easy.

The annotation is ignored and the table is created as user_connection which then causes Spring Social to have a hissy fit.

Please tell me there's some easy way to tell my Spring Boot app to just name that one table (and its corresponding columns) to use a camel-case naming convention instead of the standard one.

Wharfinger answered 28/1, 2017 at 16:22 Comment(2)
how do you configure your auto ddl creation?Hirsute
also would be good if you add you application.properties and proerties that you add to the sessionFactoryHirsute
M
13

TL; DR

Add the following to your application.yml file:

spring:
  jpa:
    hibernate:
      naming:
        physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl

Or your application.properties:

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

Detailed Answer

As Spring Boot 1.4 release notes states:

SpringNamingStrategy is no longer used as Hibernate 5.1 has removed support for the old NamingStrategy interface. A new SpringPhysicalNamingStrategy is now auto-configured which is used in combination with Hibernate’s default ImplicitNamingStrategy. This should be very close to (if not identical) to Spring Boot 1.3 defaults, however, you should check your Database schema is correct when upgrading.

This new PhysicalNamingStrategy follows Spring recommended naming conventions. Anyway if you want total control over physical naming, you're better off using the org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl. You can switch to that naming strategy by adding the following to your application.yml:

spring:
  jpa:
    hibernate:
      naming:
        physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl

The annotation is ignored and the table is created as user_connection which then causes Spring Social to have a hissy fit.

The apply method of SpringPhysicalNamingStrategy is the key to understand this behavior:

private Identifier apply(Identifier name, JdbcEnvironment jdbcEnvironment) {
    if (name == null) {
        return null;
    }
    StringBuilder builder = new StringBuilder(name.getText().replace('.', '_'));
    for (int i = 1; i < builder.length() - 1; i++) {
        if (isUnderscoreRequired(builder.charAt(i - 1), builder.charAt(i),
                builder.charAt(i + 1))) {
            builder.insert(i++, '_');
        }
    }
    return getIdentifier(builder.toString(), name.isQuoted(), jdbcEnvironment);
}

private boolean isUnderscoreRequired(char before, char current, char after) {
    return Character.isLowerCase(before) && Character.isUpperCase(current)
            && Character.isLowerCase(after);
}

It basically replaces any . and case changes (take a look at isUnderscoreRequired method) with an underscore.

Mawson answered 28/1, 2017 at 16:46 Comment(4)
I tried so many things, I've lost track. I believe when I used this method, all of the other tables and columns that weren't explicitly mapped as using underscores were recreated using camel-case. So essentially, if I use this approach, I'll have to go through every single column and table and add the annotations overriding them with the underscore notation.Wharfinger
Yeah I just tested it out and it behaves like I stated above. All tables and columns that aren't explicitly named with @Column and @Table will be created in the DB as camel-case. It sucks because I want the exact opposite effect. I want to ONLY have to explicitly map this one stupid UserConnection table, not all my other tables and columns.Wharfinger
@Wharfinger Then you should provide your own ImplicitNamingStrategyMawson
Yes I tried that too... but I didn't know how to isolate the names of the columns associated with the UserConnection table. I was able to properly name the UserConnection table, but not all the bloody columns inside of it... I didn't want to just blindly change all the columns names to be camel-case, as there could be other columns with the same names that I wouldn't want to have changed to camel-case... so, is there a way to know if a certain column belongs to a table with your own naming strategy?Wharfinger
H
0

Option 1

First of all define your tables name on the @Entity mapping:

@Entity( name = "UserConnections")
public class UserConnection{

Option 2

You should pay a bit with the NamingStrategy. When you define your properties for the sessionFactory bean then try adding this:

<prop key="hibernate.implicit_naming_strategy">legacy-jpa</prop>

When an entity does not explicitly name the database table that it maps to, we need to implicitly determine that table name. Or when a particular attribute does not explicitly name the database column that it maps to, we need to implicitly determine that column name.

So if you do not want to explicitly name your table names for each of the entities you should follow this strategy.

Option 3

Alternatively if the above do not work for you, you have to use the PhysicalNamingStrategy. Though this is the last resort in your case:

REference: https://docs.jboss.org/hibernate/orm/5.1/userguide/html_single/chapters/domain/naming.html

Hirsute answered 28/1, 2017 at 16:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.