将Hibernate 4.3迁移到5.2 - 缺少表

时间:2018-01-23 14:32:56

标签: java hibernate migration hibernate-4.x hibernate-5.x

我尝试从Hibernate 4.3迁移到5.2。 我最终遇到的问题是使用以下实体结构:

@MappedSuperclass
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Post<T> {

    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(
            name = "post_tags",
            joinColumns = {@JoinColumn(name = "post")},
            inverseJoinColumns = {@JoinColumn(name = "tag")})
    @Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
    private Set<Tag> tags = new HashSet<>();

    // ...
}


@Entity
@Table(name = "x_post")
public class XPost extends Post<X> {
    // ...
}


@Entity
@Table(name = "y_post")
public class YPost extends Post<Y> {
    // ...
}

在迁移之前,这会生成4个不同的表: x_posty_postx_post_tagsy_post_tags

现在,当我运行hibernate验证时,我得到了

  

引起:org.hibernate.tool.schema.spi.SchemaManagementException:架构验证:缺少表[post_tags]           在org.hibernate.tool.schema.internal.AbstractSchemaValidator.validateTable(AbstractSchemaValidator.java:121)           在org.hibernate.tool.schema.internal.GroupedSchemaValidatorImpl.validateTables(GroupedSchemaValidatorImpl.java:42)           在org.hibernate.tool.schema.internal.AbstractSchemaValidator.performValidation(AbstractSchemaValidator.java:89)           在org.hibernate.tool.schema.internal.AbstractSchemaValidator.doValidation(AbstractSchemaValidator.java:68)...

所以Hibernate现在希望有post_tags表,但我无法理解。

我怀疑问题与命名策略有关 - 之前我使用的是ImprovedNamingStrategy,但在迁移后我必须添加看起来像这样的自定义hibernate.physical_naming_strategy

public class MyPhysicalNamingStrategy extends PhysicalNamingStrategyStandardImpl implements
        Serializable {

    @Override
    public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment context) {
        return Identifier.toIdentifier(addUnderscores(name.getText()), name.isQuoted());
    }

    @Override
    public Identifier toPhysicalColumnName(Identifier name, JdbcEnvironment context) {
        return Identifier.toIdentifier(addUnderscores(name.getText()), name.isQuoted());
    }

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

更新[2018-01-25]

如果我从@JoinTable(name = "post_tags")字段中删除tags,则会按预期生成表:x_posty_postx_post_tagsy_post_tags 。如果我在上面的例子中保留它,它只生成post_tags表。

因此,删除@JoinTable似乎解决了这种情况下的问题,但是如果我想让联接表名称独立于字段tags(例如,如果我希望它是单数 - { {1}})我仍然需要使用*_post_tag让我回到最初的问题。

1 个答案:

答案 0 :(得分:1)

JPA规范没有规定在这种情况下应该创建2个表。

所以,在我看来,如果你明确指定了表名,那么为什么Hibernate会尝试改变呢?

因此,Hibernate 5的行为更直观。现在,当你没有指定@JoinTable并且Hibernate生成两个表而不是一个时,你有两个选择:

  1. 您从@ManyToMany中移除@MappedSuperclass并在实体X和Y中明确声明。
  2. 您离开@ManyToMany @MappedSuperclass并提供自定义PhysicalNamingStrategyStandardImpl,尝试覆盖默认toPhysicalTableName,以考虑您在{{1}中提供的值}}。