如何配置Hibernate自动将Observable类型字段标记为@Transient?
刚好我之前也处理过类似的场景,Hibernate确实没有提供直接的配置项让你全局指定某类类型自动标记为瞬态,但有几个优雅的方案能帮你摆脱重复加@Transient的繁琐工作,下面给你详细说明:
方案一:通过MetadataBuilderContributor全局修改元数据(最推荐)
这个方法是在Hibernate初始化构建元数据的时候,自动遍历所有实体的属性,把JavaFX Observable相关类型的属性标记为瞬态,一劳永逸。
步骤1:实现MetadataBuilderContributor接口
写一个Kotlin类,实现Hibernate的MetadataBuilderContributor,在里面判断属性类型是否属于Observable家族(比如ObservableValue、ObservableList、ObservableMap这些),如果是就设置为瞬态:
import org.hibernate.boot.MetadataBuilder import org.hibernate.boot.spi.MetadataBuilderContributor import org.hibernate.mapping.Property import javafx.beans.value.ObservableValue import javafx.collections.ObservableCollection class ObservableTypeTransientContributor : MetadataBuilderContributor { override fun contribute(metadataBuilder: MetadataBuilder) { val metadata = metadataBuilder.build() // 遍历所有实体绑定 metadata.entityBindings.forEach { entityBinding -> entityBinding.properties.forEach { property: Property -> val propertyClass = property.type.returnedClass // 检查是否是Observable相关类型 if (ObservableValue::class.java.isAssignableFrom(propertyClass) || ObservableCollection::class.java.isAssignableFrom(propertyClass) ) { property.isTransient = true } } } } }
步骤2:注册这个贡献者
如果用persistence.xml配置Hibernate,添加以下配置:
<property name="hibernate.metadata_builder_contributor" value="com.yourpackage.ObservableTypeTransientContributor"/>
如果是Spring Boot或者编程式配置,直接把这个类的实例注入到Hibernate的配置中即可。
方案二:自定义组合注解(语义更清晰)
如果你觉得全局修改太“隐性”,可以定义一个组合注解,把@Transient封装进去,这样给Observable属性加注解时语义更明确,而且后续如果需要调整逻辑,只需要修改这个注解:
import javax.persistence.Transient @Target(AnnotationTarget.PROPERTY) @Retention(AnnotationRetention.RUNTIME) @Transient annotation class ObservableTransient
之后你只需要给Observable属性标注@ObservableTransient,比如:
@Entity class User { @Id var id: Long = 0 @ObservableTransient val name = SimpleStringProperty("") }
这个方案虽然还是要手动加注解,但比直接用@Transient更清晰,也方便后续维护。
方案三:用Hibernate拦截器在运行时处理
这种方式是在Hibernate准备持久化对象时,跳过Observable类型的属性。不过这个方案是运行时处理,不如元数据修改彻底,适合临时场景:
import org.hibernate.EmptyInterceptor import org.hibernate.type.Type import javafx.beans.value.ObservableValue import javafx.collections.ObservableCollection class ObservableTransientInterceptor : EmptyInterceptor() { override fun onSave(entity: Any, id: Any?, state: Array<Any?>, propertyNames: Array<String?>, types: Array<Type?>): Boolean { state.forEachIndexed { index, value -> value?.javaClass?.let { clazz -> if (ObservableValue::class.java.isAssignableFrom(clazz) || ObservableCollection::class.java.isAssignableFrom(clazz) ) { state[index] = null // 清空该属性,避免持久化 } } } return super.onSave(entity, id, state, propertyNames, types) } }
注册这个拦截器到Hibernate配置中即可生效。
总结:最推荐方案一,一次性解决所有Observable类型的瞬态问题,完全不需要手动加注解,完美匹配你的需求。
内容的提问来源于stack exchange,提问作者bkenn

