我正在做一个Java项目,这个项目很多年前就开始了,最初的开发人员都早已不在了,我继承的一个类是Hibernate NamingStrategy接口的一个实现。
现在NamingStrategy已经被弃用了,我想过渡到一个仍然支持的版本。不幸的是,我不知道该怎么做。我已经看到了关于这个主题的两种建议:大多数在线用户推荐使用隐式命名策略和物理命名策略,而Hibernate Javadoc推荐使用命名策略代理。
在这两种情况下,对于一个不成熟的Hibernate用户来说,可用的信息不足以理解如何进行迁移。NamingStrategy有10个方法,每个方法都接受字符串参数。PhysicalNamingStrategy有5个方法,每个方法都不接受字符串参数。
有人能帮助我找到安全的解决方法吗?如果有帮助的话,我在下面附上了我们的NamingStrategy实现。
package gov.nasa.ziggy.services.database;
import javax.persistence.Column;
import javax.persistence.Table;
import org.hibernate.AssertionFailure;
import org.hibernate.cfg.NamingStrategy;
import org.hibernate.internal.util.StringHelper;
import gov.nasa.ziggy.util.StringUtils;
import gov.nasa.ziggy.util.StringUtils.TextCase;
/**
* This class implements {@link org.hibernate.cfg.NamingStrategy} for the database naming
* conventions defined for the Ziggy project. Essentially, this consists of converting the Java
* camel-case names to an all-caps with underscores format.
* <p>
* This code is based on {@link org.hibernate.cfg.ImprovedNamingStrategy}, the main difference being
* that names that are explicitly defined in the code annotations (like {@link Table},
* {@link Column}, etc.) are not modified.
*
*/
public class ZiggyNamingStrategy implements NamingStrategy {
/**
* A convenient singleton instance
*/
public static final NamingStrategy INSTANCE = new ZiggyNamingStrategy();
/**
* Return the unqualified class name, mixed case converted to underscores
*/
@Override
public String classToTableName(String className) {
return addUnderscores(StringHelper.unqualify(className));
}
/**
* Return the full property path with underscore seperators, mixed case converted to underscores
*/
@Override
public String propertyToColumnName(String propertyName) {
return addUnderscores(StringHelper.unqualify(propertyName));
}
/**
* This method is called for names explicitly defined in the annotations. Leave the name alone!
*/
@Override
public String tableName(String tableName) {
return tableName;
}
/**
* This method is called for names explicitly defined in the annotations. Leave the name alone!
*/
@Override
public String columnName(String columnName) {
return columnName;
}
@Override
public String collectionTableName(String ownerEntity, String ownerEntityTable,
String associatedEntity, String associatedEntityTable, String propertyName) {
String s = tableName(ownerEntityTable + '_' + propertyToColumnName(propertyName));
System.out.println("collection table name " + s);
return s;
}
/**
* Return the argument
*/
@Override
public String joinKeyColumnName(String joinedColumn, String joinedTable) {
String s = addUnderscores(joinedTable) + "_" + addUnderscores(joinedColumn);
System.out.println("joinkey column name " + s);
return s;
}
/**
* Return the property name or propertyTableName
*/
@Override
public String foreignKeyColumnName(String propertyName, String propertyEntityName,
String propertyTableName, String referencedColumnName) {
String header = propertyName != null ? StringHelper.unqualify(propertyName)
: propertyTableName;
if (header == null) {
throw new AssertionFailure("NamingStrategy not properly filled");
}
String s = addUnderscores(propertyTableName) + "_" + addUnderscores(referencedColumnName);
if (s.equals("PI_PS_NAME_NAME")) {
System.out.println("foreign key column name " + s);
}
return s;
}
/**
* Return the column name or the unqualified property name
*/
@Override
public String logicalColumnName(String columnName, String propertyName) {
String s = StringHelper.isNotEmpty(columnName) ? columnName
: StringHelper.unqualify(propertyName);
if (columnName == null) {
System.out
.println("logical column name " + columnName + " " + propertyName + " " + s);
}
return s;
}
/**
* Returns either the table name if explicit or if there is an associated table, the
* concatenation of owner entity table and associated table otherwise the concatenation of owner
* entity table and the unqualified property name
*/
@Override
public String logicalCollectionTableName(String tableName, String ownerEntityTable,
String associatedEntityTable, String propertyName) {
if (tableName != null) {
return tableName;
}
// use of a stringbuffer to workaround a JDK bug
String s = new StringBuffer(ownerEntityTable).append("_")
.append(associatedEntityTable != null ? associatedEntityTable
: StringHelper.unqualify(propertyName))
.toString();
System.out.println("logical collection table name " + s);
return s;
}
/**
* Return the column name if explicit or the concatenation of the property name and the
* referenced column
*/
@Override
public String logicalCollectionColumnName(String columnName, String propertyName,
String referencedColumn) {
String s = StringHelper.isNotEmpty(columnName) ? columnName
: StringHelper.unqualify(propertyName) + "_" + referencedColumn;
if (!s.equals(columnName)) {
System.out.println("logical collection column name " + columnName + " " + propertyName
+ " " + referencedColumn + " " + s);
}
return s;
}
protected String addUnderscores(String original) {
return StringUtils.camelCaseToUnderscores(original, TextCase.UPPER);
}
}
2条答案
按热度按时间rqenqsqc1#
所以我最近重写了这些接口的Javadoc,以便于理解它们之间的区别,但是新的Javadoc还不能在线使用,因为6.2 final的发布推迟了一周。
所以让我复制/粘贴Javadoc中的解释,HTH。
Package
org.hibernate.boot.model.naming
此API允许泛型代码在确定数据库对象(表、列和约束)名称的过程中进行干预。
名称确定分为两个阶段:
1.* 逻辑命名 * 是应用命名规则来确定在O/RMap中未显式分配名称的对象的名称的过程。
在这里,这是
org.hibernate.boot.model.naming.ImplicitNamingStrategy
实现的职责。1.* 物理命名 * 是应用附加规则将逻辑名称转换为将在数据库中使用的实际"物理"名称的过程。例如,规则可能包括使用标准化缩写或修剪标识符长度等内容。
在这里,这是
PhysicalNamingStrategy
实现的职责。ImplicitNamingStrategy
一组规则,用于在Java域模型元素的Map未显式指定(既未在Java代码注解中指定,也未在基于XML的Map文档中指定)时确定Map关系数据库对象的逻辑名称。
例如,如果注解为
@Entity
的Java类没有@Table
注解,则使用ImplicitEntityNameSource
调用determinePrimaryTableName
,以提供对有关Java类及其实体名称的信息的访问。另一方面,当明确指定逻辑名时,例如,使用
@Table
来指定表名,或者使用@Column
来指定列名,则不调用PhysicalNamingStrategy
,并且PhysicalNamingStrategy
没有机会干预逻辑名的确定。然而,通过
org.hibernate.boot.model.naming.ImplicitNamingStrategy
将进一步的处理级别应用于所得到的逻辑名称,以便确定关系数据库模式中的"最终最终"物理名称。强烈建议使用自定义的ImplicitNamingStrategy
,而不要使用繁琐和重复的显式表名和列名Map。我们预计大多数使用Hibernate的项目将以ImplicitNamingStrategy
的定制实现为特色。可以使用配置属性
"hibernate.implicit_naming_strategy"
来选择ImplicitNamingStrategy
。PhysicalNamingStrategy
一组规则,用于根据对象/关系Map所指定的逻辑名来确定关系数据库架构中对象的物理名。
逻辑名称在Map和数据库模式之间提供了一个额外的间接级别,并且
PhysicalNamingStrategy
甚至允许在关系模式的特征特别不优雅的遗留命名约定的情况下在Map中使用更"自然"的命名,例如,它可以保护Map不受老式实践的影响,比如在表名前面加上TBL_
。但是,请注意,手写的原生SQL必须以物理名称的形式编写,因此这里的抽象在某种意义上是"不完整的"。
可以使用配置属性
"hibernate.physical_naming_strategy"
来选择PhysicalNamingStrategy
。gxwragnw2#
小故事
不要使用
Hibernate
中的命名策略,这个特性不稳定、不可靠、不可维护,而且还会增加技术债务(这正是您实际得到的:* 此时NamingStrategy已弃用,我希望过渡到将来仍受支持的功能 *),此外,即使Hibernate
团队也承认此功能不稳定:孵育时:
将某些包、类型等标记为孵化中,可能是递归的。孵化表示某些东西仍在积极开发中,因此可能在以后更改;“技术预览”。
这些类型和方法的用户被认为是早期采用者,他们帮助形成这些类型/方法的最终定义沿着消费者的需求。
最好的选择是在相关实体/字段上放置有效/实际的
@Table
和@Column
注解,并结束技术债务--作为开发人员,保持代码可维护是您的责任。Hibernate
团队无意中打开了潘多拉的盒子,即将发布的6.2版本是关闭它的最佳候选版本,唯一需要的操作是将@Incubating
替换为@Deprecated
。"说来话长"
I.命名策略不能跨JPA实现移植,例如,如果您试图找到如何在
eclipselink
中实现相同的策略,您可能会发现something like:抱歉,但这不是我想要维护的代码,另一方面,我可以肯定地说
eclipselink
不是我想要处理的JPA
实现-问题是它严格遵循JPA
规范(Hibernate
肯定更加灵活和可扩展)但是,您需要记住,命名策略是全局适用的,因此,当您采用基于JPA
的第三方库或插件时,您可能会“惊讶”该库或插件与您的命名策略冲突。二、可预测的名字有意义:
spring-data-jpa
的命名约定说声“谢谢”),这需要花时间将SQL查询与JPQL查询进行匹配,如果您认为SQL查询没有意义并且可以使用micrometer
/grafana
收集性能统计信息,我有个坏消息要告诉你that does not work in HibernateUK_jymdjmt0g2vxkk0fp56xlhjud
的索引覆盖了哪些列。需要询问DBA吗?好吧,您的代码是不可维护的...维护有关数据库的单一真实来源,并在源代码中保留尽可能多的信息hibernate.hbm2ddl.auto=validate
-它的功能极其有限)III.特征被破坏
小测验:
问:当
InheritanceType=JOINED
:A:
Hibernate
同时接受逻辑表名和物理表名。Q:如果您创建了一个“视图”,并且希望保持视图状态与持久性上下文同步,那么您需要在
@Synchronize
注解中指定什么:A:一个
Q:您需要触发一个SQL过程/更新语句,并且希望它的执行与持久化上下文保持同步,您需要在
org.hibernate.query.native.spaces
hint中指定什么(另一个概念,没有描述):A:您需要指定您认为可行的所有内容:物理表名、逻辑表名、实体名、高速缓存区域名、母亲的婚前姓、第一只宠物的名字等--没有人知道如何正确使用这些名称,例如Thorben Janssen认为we need to pass class name there,
Hibernate
假定查询空间实际上是一个物理表名(如何使用@jakarta.persistence.QueryHint
注解将实体类作为提示值传递?)即使Hibernate
项目主管has no idea about how to use that properly:逻辑名称是在Java代码和XMLMap文档的注解中使用的名称
如果是
@jakarta.persistence.QueryHint
,我们需要使用物理表名!逻辑在哪里???