Reputation: 7428
I'm trying to migrate from Hibernate 4.3 to 5.2. The problem I end up having is with the following entity structure:
@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> {
// ...
}
Before the migration this generated 4 different tables:
x_post
, y_post
, x_post_tags
, y_post_tags
Now when I run the hibernate validation I get
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)...
So Hibernate expects to have table post_tags
now but I can't get why.
I suspect the problem is related to the naming strategy - previously I was using the ImprovedNamingStrategy
but after the migration I had to add custom hibernate.physical_naming_strategy
that looks like that:
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);
}
}
Update [2018-01-25]:
If I remove the @JoinTable(name = "post_tags")
from the tags
field the tables are generated as expected: x_post
, y_post
, x_post_tags
, y_post_tags
. If I leave it as it is in the example above it only generates the post_tags
table.
So removing @JoinTable
seem to fix the issue in that case, but if I want to have the join table name independent of the field tags
(ex. if I want it to be singular - *_post_tag
) I still need to use the @JoinTable
which brings me back to the initial problem.
Upvotes: 1
Views: 1002
Reputation: 153780
The JPA spec does not specify that 2 tables should be created in this case.
So, in my opinion, if you explicitly specify the table name, then why would Hibernate try to change that?
So, the Hibernate 5 behavior is more intuitive. Now, when you don't specify the @JoinTable
and Hibernate generates two tables instead of one, you have two choices:
@ManyToMany
from the @MappedSuperclass
and declare it explicitly in entities X and Y.@ManyToMany
from the @MappedSuperclass
and provide a custom PhysicalNamingStrategyStandardImpl
that tries to override the default toPhysicalTableName
to take into consideration the values you provided in @JoinTable
.Upvotes: 2