【发布时间】: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_post、y_post、x_post_tags、y_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_post、y_post、x_post_tags、y_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