Hibernate 5隐式策略和唯一键

时间:2016-07-06 08:34:29

标签: java hibernate hibernate-5.x

我正在从php / doctrine迁移到java / hibernate。在这种情况下,我需要hibernate中的命名策略应该与doctrine中的相同。

所以,我已经实现了自定义ImplicitNamingStrategy。 我使用 fk_XXX uniq_XXX idx_XXX 作为索引命名的模板。 外键工作正常,但唯一键没有。似乎hibernate使用旧命名策略来获取唯一键。我知道了 控制台中的下一条消息:

index.js

因此,在我的策略中,这种键应该命名为uniq_XXX。是否可以将所有唯一键的命名替换为我的策略?

更新

像这样声明的约束可以正常工作:

constraint "uk_g8hr207ijpxlwu10pewyo65gv" of relation "language" does not exist, skipping

像这样声明的Constrints有问题:

@Table(uniqueConstraints = {@UniqueConstraint(columnNames = "display_number")})

ImplicitNamingStrategyDoctrineImpl.java:

@Column(nullable = true, unique = true) 
protected Integer displayNumber;

DoctrineNamingHelper.java:

package ru.tvip.support.naming;

import org.hibernate.HibernateException;
import org.hibernate.boot.model.naming.*;
import org.hibernate.boot.model.source.spi.AttributePath;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.internal.util.StringHelper;

import java.io.Serializable;
import java.util.Locale;

/**
* Emulates PHP Doctrine naming strategy.
*/
public class ImplicitNamingStrategyDoctrineImpl implements ImplicitNamingStrategy, Serializable {

    @Override
    public Identifier determinePrimaryTableName(ImplicitEntityNameSource source) {
        if ( source == null ) {
            // should never happen, but to be defensive...
            throw new HibernateException( "Entity naming information was not provided." );
        }

        String tableName = transformEntityName( source.getEntityNaming() );

        if ( tableName == null ) {
            throw new HibernateException( "Could not determine primary table name for entity" );
        }

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


    @Override
    public Identifier determineJoinTableName(ImplicitJoinTableNameSource source) {

        final String name = transformEntityName( source.getOwningEntityNaming() )
                        + '_'
                        + transformEntityName( source.getNonOwningEntityNaming());

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


    @Override
    public Identifier determineCollectionTableName(ImplicitCollectionTableNameSource source) {

        final String entityName = transformEntityName( source.getOwningEntityNaming() );

        final String name = entityName
                + '_'
                + transformAttributePath( source.getOwningAttributePath() );

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

    @Override
    public Identifier determineIdentifierColumnName(ImplicitIdentifierColumnNameSource source) {

        return toIdentifier(
                transformAttributePath( source.getIdentifierAttributePath() ),
                source.getBuildingContext()
        );
    }

    @Override
    public Identifier determineDiscriminatorColumnName(ImplicitDiscriminatorColumnNameSource source) {
        return toIdentifier(
                source.getBuildingContext().getMappingDefaults().getImplicitDiscriminatorColumnName(),
                source.getBuildingContext()
        );
    }

    @Override
    public Identifier determineTenantIdColumnName(ImplicitTenantIdColumnNameSource source) {
        return toIdentifier(
                source.getBuildingContext().getMappingDefaults().getImplicitTenantIdColumnName(),
                source.getBuildingContext()
        );
    }

    @Override
    public Identifier determineBasicColumnName(ImplicitBasicColumnNameSource source) {

        String name = transformAttributePath( source.getAttributePath() );

        name = addUnderscores(name);

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

    @Override
    public Identifier determineJoinColumnName(ImplicitJoinColumnNameSource source) {
        // JPA states we should use the following as default:
        //
        //  (1) if there is a "referencing relationship property":
        //      "The concatenation of the following: the name of the referencing relationship
        //          property or field of the referencing entity or embeddable class; "_"; the
        //          name of the referenced primary key column."
        //
        //  (2) if there is no such "referencing relationship property", or if the association is
        //          an element collection:
        //     "The concatenation of the following: the name of the entity; "_"; the name of the
        //          referenced primary key column"

        // todo : we need to better account for "referencing relationship property"

        final String name;

        //FIXME: This not handle manytomany relations. Doctrine using attribute name as reference column - Pavel Sokolov

        /*
        // For debug:
        String soruceEntityName=source.getEntityNaming().getEntityName();
        String sourceEntityColumn=source.getAttributePath().getProperty();
        String referencedColumnName=source.getReferencedColumnName().getText();
        ImplicitJoinColumnNameSource.Nature nature = source.getNature();
        */

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

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

    @Override
    public Identifier determinePrimaryKeyJoinColumnName(ImplicitPrimaryKeyJoinColumnNameSource source) {
        // JPA states we should use the following as default:
        //      "the same name as the primary key column [of the referenced table]"
        return source.getReferencedPrimaryKeyColumnName();
    }

    @Override
    public Identifier determineAnyDiscriminatorColumnName(ImplicitAnyDiscriminatorColumnNameSource source) {
        return toIdentifier(
                transformAttributePath( source.getAttributePath() ) + "_" + source.getBuildingContext().getMappingDefaults().getImplicitDiscriminatorColumnName(),
                source.getBuildingContext()
        );
    }

    @Override
    public Identifier determineAnyKeyColumnName(ImplicitAnyKeyColumnNameSource source) {
        return toIdentifier(
                transformAttributePath( source.getAttributePath() ) + "_" + source.getBuildingContext().getMappingDefaults().getImplicitIdColumnName(),
                source.getBuildingContext()
        );
    }


    @Override
    public Identifier determineMapKeyColumnName(ImplicitMapKeyColumnNameSource source) {
        return toIdentifier(
                transformAttributePath( source.getPluralAttributePath() ) + "_KEY",
                source.getBuildingContext()
        );
    }

    @Override
    public Identifier determineListIndexColumnName(ImplicitIndexColumnNameSource source) {
        return toIdentifier(
                transformAttributePath( source.getPluralAttributePath() ) + "_ORDER",
                source.getBuildingContext()
        );
    }

    @Override
    public Identifier determineForeignKeyName(ImplicitForeignKeyNameSource source) {
        return toIdentifier(
                DoctrineNamingHelper.INSTANCE.generateHashedFkName(
                        "fk_",
                        source.getTableName(),
                        source.getReferencedTableName(),
                        source.getColumnNames()
                ),
                source.getBuildingContext()
        );
    }

    @Override
    public Identifier determineUniqueKeyName(ImplicitUniqueKeyNameSource source) {
        return toIdentifier(
                DoctrineNamingHelper.INSTANCE.generateHashedConstraintName(
                        "uniq_",
                        source.getTableName(),
                        source.getColumnNames()
                ),
                source.getBuildingContext()
        );
    }

    @Override
    public Identifier determineIndexName(ImplicitIndexNameSource source) {
        return toIdentifier(
                DoctrineNamingHelper.INSTANCE.generateHashedConstraintName(
                        "idx_",
                        source.getTableName(),
                        source.getColumnNames()
                ),
                source.getBuildingContext()
        );
    }

    protected Identifier toIdentifier(String stringForm, MetadataBuildingContext buildingContext) {
        return buildingContext.getMetadataCollector()
                .getDatabase()
                .getJdbcEnvironment()
                .getIdentifierHelper()
                .toIdentifier( stringForm );
    }

    private String transformAttributePath(AttributePath attributePath) {
        return addUnderscores(attributePath.getProperty());
    }

    protected String transformEntityName(EntityNaming entityNaming) {

        String name=entityNaming.getEntityName();

        name = StringHelper.unqualify( name );

        name = addUnderscores(name);

        return name;
    }

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

1 个答案:

答案 0 :(得分:0)

在这个游戏上有点晚了。我看到了5.4.6.Final的问题;似乎仍然是一个未解决的问题: