由于历史原因,我有一个名为
User
的实体类,Hibernate 默认计算表名称为 user
。该名称是一个保留的 SQL 关键字,至少在 Postgres 上无需引用即可中断,但它可以在 DB2i 等其他 RDBMS 上工作。此外,DB2i 不仅使用该不带引号的名称,而且由于它不带引号,因此还应用大写名称折叠。这意味着在生产中一些名为 USER
的表已经存在。虽然 Postgres 不支持这种不带引号的具体表名称,但它可以创建其他表,但应用小写名称折叠,因此当前 RDBMS 之间的表命名方案有所不同。
这就是事情变得困难的地方:理论上,最好的方法是始终简单地引用所有标识符,但从一开始就不是这样,所以我现在有小写和大写的表名,具体取决于 RDBMS用过的。这意味着在 DB2i 上将值引用到
user
失败,但在 Postgres 上可以。将值引用到 USER
在 DB2i 上有效,但至少在 Postgres 上看起来很奇怪,因为其他名称都是小写的。
我知道该问题还有许多其他可能的解决方案,例如引用和重命名所有内容、仅将一张表重命名为
user_account
、实施不同的自定义命名策略等。但我想知道的是是否可以应用同一类有两个不同的 @Table
注释,具体取决于某些 Spring 属性。类似于以下内容,仅具有一个且相同的类:
@ConditionalOnProperty(
value="spring.jpa.properties.hibernate.dialect",
havingValue = "com.ibm.as400.access.AS400JDBCDriver"
matchIfMissing = true)
@Table(name = "\"user\"")
public class User extends BusinessEntity {
与
@ConditionalOnProperty(
value="spring.jpa.properties.hibernate.dialect",
havingValue = "com.ibm.as400.access.AS400JDBCDriver"
matchIfMissing = false)
@Table(name = "\"USER\"")
public class User extends BusinessEntity {
在上面的示例中,
@ConditionalOnProperty
的目标是类,而不是 @Table
。我希望 @Table
取决于属性。
那么,类似的事情有可能吗?
谢谢!
有几个选项可以解决您的问题(所有这些选项实际上都很糟糕,因为最好的选择是重命名表):
将
hibernate.auto_quote_keyword
设置为 true
,因为 这是 Mark Rotteveel 的建议
利用物理命名策略,例如:
public class ReservedWordAwareCamelCaseToUnderscoresNamingStrategy extends CamelCaseToUnderscoresNamingStrategy {
@Override
public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment jdbcEnvironment) {
Identifier suggested = super.toPhysicalTableName(name, jdbcEnvironment);
Dialect dialect = jdbcEnvironment.getDialect();
if (...) {
return ...
}
return suggested;
}
}
Integrator
SPI:public class LegacyUserTableNameIntegrator implements Integrator {
@Override
public void integrate(Metadata metadata, SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) {
Dialect dialect = serviceRegistry.getService(JdbcEnvironment.class).getDialect();
for (PersistentClass persistentClass : metadata.getEntityBindings()) {
if (persistentClass.getMappedClass() == User.class) {
persistentClass.getRootClass().getTable().setName("...");
}
}
}
...
}