1

I am trying to add underscores for the foreign key column names by overriding the method determineForeignKeyName in ImplicitNamingStrategyJpaCompliantImpl class, but somehow its not working. Below is the class i created,

public class CustomNamingStrategy extends ImplicitNamingStrategyJpaCompliantImpl implements Serializable{

    public static final CustomNamingStrategy INSTANCE=new CustomNamingStrategy ();



    /**
     * Produces a plural table name from the given class name
     * @return a pluralized version of the class name using underscores instead of mixed case.
     */
    @Override
    protected String transformEntityName(EntityNaming entityNaming) {
        return Noun.pluralOf(addUnderscores(StringHelper.unqualify(entityNaming.getEntityName())));
    }

    protected static String addUnderscores(String name) {
        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);
    }

    @Override
    public Identifier determineForeignKeyName(ImplicitForeignKeyNameSource source) {

        return toIdentifier(
                NamingHelper.INSTANCE.generateHashedFkName(
                        "FK",
                        source.getTableName(),
                        source.getReferencedTableName(),
                        addUnderscorestocolumns(source.getColumnNames())
                ),
                source.getBuildingContext()
        );
    }


    public List<Identifier> addUnderscorestocolumns(List<Identifier> columnNamesList) {

        List<Identifier> underscorecolumns = new ArrayList<Identifier>();

        for (int i = 0; i < columnNamesList.size(); i++) {
                        underscorecolumns.add(Identifier.toIdentifier(addUnderscores(columnNamesList.get(i).getText())))  ;
        }
        return underscorecolumns;
    }



   @Override
    public Identifier determineBasicColumnName(ImplicitBasicColumnNameSource source) {

        return toIdentifier(transformAttributePathCustom(source.getAttributePath()), source.getBuildingContext());
    }

    protected String transformAttributePathCustom(AttributePath attributePath) {
        return addUnderscores(attributePath.getProperty());
    }

  }

So, except the determineForeignKeyName method, others methods are working as expected, like adding plural names and underscore for the tables. When i debug through the code, i can see the control going into the determineForeignKeyName method for the foreign key columns and underscores are added, but when the control goes to InflightMetadataCollectorImpl class (org.hibernate.boot.internal), i can see only referenced column is added, but not the underscores for the column name.

Is there any other method i need to implement for foreign key column names or i there any error in my implementation? Please suggest.

Stan
  • 23
  • 5

2 Answers2

2

NamingHelper.INSTANCE.generateHashedFkName() generates a hashed name. You need something like this

@Override
public Identifier determineForeignKeyName(ImplicitForeignKeyNameSource source) {
    return toIdentifier(
                "FK_" +
                source.getTableName().getText() + "_" +
                source.getReferencedTableName().getText() + "_" +
              addUnderscorestocolumns(source.getColumnNames()),
        source.getBuildingContext());
}

You can refer as an example Hibernate5NamingStrategy

The method Identifier determineForeignKeyName(ImplicitForeignKeyNameSource source) is not used to generate column names, but foreign key constraint names like F_users_fk_address for this SQL

alter table users 
  add constraint F_users_fk_address 
  foreign key (fk_address) 
  references user_addresses (f_pid)

To specify foreign key column names you need to override this method

Identifier determineJoinColumnName(ImplicitJoinColumnNameSource source)

Refer this: JoinColumnStrategyTest.java

v.ladynev
  • 19,275
  • 8
  • 46
  • 67
  • Hi, above code is working fine and it is forming the below name identifier for userprofile foreign key column in Users table. "FK_users_profiles_[user_profile_id]". But when the application is trying to retrieve the records, in the query again it is referencing userprofile_id instead of user_profile_id. – Stan May 13 '16 at 13:47
  • Previously we used hibernate 4 and i upgraded it to hibernate 5. Below is the user class code @OneToOne(orphanRemoval = true) @Cascade(org.hibernate.annotations.CascadeType.ALL) public Profile getUserProfile() { return userProfile; } public void setUserProfile(Profile userProfile) { this.userProfile = userProfile; } – Stan May 13 '16 at 13:55
  • Its working. Not able to up vote the answer as i don't have enough points. – Stan May 13 '16 at 14:36
1

As suggested by v.ladynev i override the determineJoinColumnName method in my class,

@Override
    public Identifier determineJoinColumnName(ImplicitJoinColumnNameSource source) {
        final String name;

        if ( source.getNature() == ImplicitJoinColumnNameSource.Nature.ELEMENT_COLLECTION
                || source.getAttributePath() == null ) {
            name = transformEntityName( source.getEntityNaming() )
                    + '_'
                    + source.getReferencedColumnName();
        }
        else {
            name = transformAttributePathCustom(source.getAttributePath())
                    + '_'
                    + source.getReferencedColumnName();
        }

        return toIdentifier( name, source.getBuildingContext() );
    }

Now its working as expected.

Stan
  • 23
  • 5