将 Hibernate 4.3 迁移到 5.2 - 缺少 table
Migrate Hibernate 4.3 to 5.2 - missing table
我正在尝试从 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 个不同的 tables:
x_post
、y_post
、x_post_tags
、y_post_tags
现在,当我 运行 休眠验证时,我得到
Caused by: org.hibernate.tool.schema.spi.SchemaManagementException: Schema-validation: missing table [post_tags]
at org.hibernate.tool.schema.internal.AbstractSchemaValidator.validateTable(AbstractSchemaValidator.java:121)
at org.hibernate.tool.schema.internal.GroupedSchemaValidatorImpl.validateTables(GroupedSchemaValidatorImpl.java:42)
at org.hibernate.tool.schema.internal.AbstractSchemaValidator.performValidation(AbstractSchemaValidator.java:89)
at org.hibernate.tool.schema.internal.AbstractSchemaValidator.doValidation(AbstractSchemaValidator.java:68)...
所以 Hibernate 现在希望有 table 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")
,则会按预期生成 table:x_post
、y_post
、x_post_tags
, y_post_tags
.如果我在上面的示例中保留它,它只会生成 post_tags
table.
所以删除 @JoinTable
似乎解决了这种情况下的问题,但是如果我想让连接 table 名称独立于字段 tags
(例如,如果我想要它是单数的 - *_post_tag
) 我仍然需要使用 @JoinTable
这让我回到最初的问题。
JPA 规范未指定在这种情况下应创建 2 table。
所以,在我看来,如果您明确指定 table 名称,那么为什么 Hibernate 会尝试更改它?
因此,Hibernate 5 的行为更加直观。现在,当您不指定 @JoinTable
并且 Hibernate 生成两个 table 而不是一个时,您有两个选择:
- 要么从
@MappedSuperclass
中删除 @ManyToMany
并在实体 X 和 Y 中明确声明它。
- 您从
@MappedSuperclass
中保留 @ManyToMany
并提供一个自定义 PhysicalNamingStrategyStandardImpl
试图覆盖默认值 toPhysicalTableName
以考虑您在 @JoinTable
.
我正在尝试从 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 个不同的 tables:
x_post
、y_post
、x_post_tags
、y_post_tags
现在,当我 运行 休眠验证时,我得到
Caused by: org.hibernate.tool.schema.spi.SchemaManagementException: Schema-validation: missing table [post_tags] at org.hibernate.tool.schema.internal.AbstractSchemaValidator.validateTable(AbstractSchemaValidator.java:121) at org.hibernate.tool.schema.internal.GroupedSchemaValidatorImpl.validateTables(GroupedSchemaValidatorImpl.java:42) at org.hibernate.tool.schema.internal.AbstractSchemaValidator.performValidation(AbstractSchemaValidator.java:89) at org.hibernate.tool.schema.internal.AbstractSchemaValidator.doValidation(AbstractSchemaValidator.java:68)...
所以 Hibernate 现在希望有 table 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")
,则会按预期生成 table:x_post
、y_post
、x_post_tags
, y_post_tags
.如果我在上面的示例中保留它,它只会生成 post_tags
table.
所以删除 @JoinTable
似乎解决了这种情况下的问题,但是如果我想让连接 table 名称独立于字段 tags
(例如,如果我想要它是单数的 - *_post_tag
) 我仍然需要使用 @JoinTable
这让我回到最初的问题。
JPA 规范未指定在这种情况下应创建 2 table。
所以,在我看来,如果您明确指定 table 名称,那么为什么 Hibernate 会尝试更改它?
因此,Hibernate 5 的行为更加直观。现在,当您不指定 @JoinTable
并且 Hibernate 生成两个 table 而不是一个时,您有两个选择:
- 要么从
@MappedSuperclass
中删除@ManyToMany
并在实体 X 和 Y 中明确声明它。 - 您从
@MappedSuperclass
中保留@ManyToMany
并提供一个自定义PhysicalNamingStrategyStandardImpl
试图覆盖默认值toPhysicalTableName
以考虑您在@JoinTable
.