【问题标题】:Migrate Hibernate 4.3 to 5.2 - missing table将 Hibernate 4.3 迁移到 5.2 - 缺少表
【发布时间】:2018-07-02 10:02:21
【问题描述】:

我正在尝试从 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

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

原因:org.hibernate.tool.schema.spi.SchemaManagementException: Schema-validation: missing table [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]

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

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

【问题讨论】:

  • 你告诉连接表被命名为“post_tags”。为什么你会期望表名不同呢? Hibernate 评估连接表的名称并将其传递给您的命名策略。
  • 我希望生成与迁移到 Hibernate 5 之前相同的表。我现在还没有添加 JoinTable 注释。它是迁移前遗留下来的。
  • 这正是阅读迁移文档很重要的原因。对于 Hibernate 的每个次要和主要版本,通常都会有新的配置参数或策略更改以支持更好、通常更有效的做事方式。在某些情况下,您可以设置一个配置选项来获取旧版行为,而在其他情况下,如果您希望旧版应用程序继续以旧版方式运行,您可能必须提供自定义实现作为迁移的一部分。
  • @Naros 是的,保持我的应用程序的遗留行为正是我想要实现的。我已经阅读了github.com/hibernate/hibernate-orm/blob/5.0/… 此处的迁移页面,并尝试按照 Changed setting defaults 部分中的建议将隐式策略设置为“legacy-hbm”来解决我的迁移问题,但没有成功。如果您有更具体的建议,我很乐意尝试一下。

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


【解决方案1】:

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

所以,在我看来,如果您明确指定表名,那么 Hibernate 为什么要尝试更改它?

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

  1. 要么从 @MappedSuperclass 中删除 @ManyToMany,然后在实体 X 和 Y 中显式声明它。
  2. 您将@ManyToMany@MappedSuperclass 分开,并提供一个自定义PhysicalNamingStrategyStandardImpl,该PhysicalNamingStrategyStandardImpl 尝试覆盖默认toPhysicalTableName 以考虑您在@JoinTable 中提供的值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-09-25
    • 2018-10-16
    • 2018-04-15
    • 2018-11-27
    • 2015-03-11
    • 1970-01-01
    • 2020-07-26
    • 1970-01-01
    相关资源
    最近更新 更多