【发布时间】:2020-10-27 17:32:59
【问题描述】:
我有一个 spring + Data JPA 设置,其中包含几个继承自这样的接口定义的实体(在“伪”Java 中):
@Entity
A implements WithSubProperty
@Id
Long Id
SubProperty subProperty
…
@Entity
B implements WithSubProperty
@Id
Long Id
SubProperty subProperty
…
Interface WithSubProperty
SubProperty subProperty
…
@Entity
SubProperty
@Id
Long Id
…
每个实体都有自己的表。 此外,还有几个使用接口定义的存储库片段(为了只为兼容的类实现一次自定义逻辑),如下所示:
RepositoryFragment<WithSubProperty, K>
List<WithSubProperty> findAllWithSubProperty(SubProperty subProperty)
…
现在,我想以相同的方式处理实际的接口属性 (SubProperty),而不必为这个单一实体复制和调整 RepositoryFragment 逻辑。我尝试了以下方法(在 SubProperty 上使用了几种不同的注释(@OneToOne、@Transient、@Column、@JoinColumm、@Formula 及其组合):
@Entity
SubProperty implements WithSubProperty
@Id
Long Id
@XXXAnnotations
SubProperty subProperty
一个想法是引用 id 列,基本上与自身形成 OneToOne 关系。到目前为止,我无法让它工作。 乍一看,这种方法看起来有点尴尬,但除了可能(?)缺乏 JPA/Hibernate 的支持以及最终导致递归的风险之外,不应该存在其他问题。想法?谢谢!
更新: 这是一个最小(非)工作示例:https://github.com/user462982/demoJPA/blob/master/src/main/java/com/example/demo/entities/SubProperty.java
对于上述代码可能造成的混乱,我深表歉意。我的原始代码在 Kotlin 中,我试图从头顶将其转换为 Java,而没有预料/考虑样板 Java 的真正获取方式(例如,Java 中没有接口属性)...... 希望工作示例现在更清楚。它在启动时会创建相同的异常,因此我假设(字节)代码是等效的。
【问题讨论】:
-
我不太确定您尝试实现什么映射。你要几张桌子?
A和B,或A和B和SubProperty。您是否考虑过为您的WithSubProperty接口使用MappedSuperclass?无论如何,我认为您不会想要引入 OneToOne 关系,除非您实际上在实体之间存在关系(例如,一个人与另一个人相关)。一般来说,在 Spring Data 中应该可以创建一个共享的基础存储库以避免重复代码,而无需向映射添加新关系。 -
@DarioSeidl 所说的,另外,如果您想用一种存储库方法处理所有实体,您可以尝试使用
@Query("SELECT e FROM #{#entityName} WHERE e.subProperty = :subProperty") -
我链接了一个 MWE 以使情况更清楚。 @DarioSeidl 由于 SubProperty 只是许多可能的接口之一,因此 MappedSuperclass 将不起作用。我实际上不想要任何关系,这些只是解决方法,以便以某种符合 JPA 的方式自行引用实体(实例)。
-
好的,不是直接回答你的问题,但我个人发现在 JPA/Hibernate 中使用(太多)继承效果不好(很难得到正确的映射,甚至更难获得正确的性能)。我最多坚持一层(单表)继承。您可以在一个层次结构中拥有多个 MappedSuperclass,并且可以很好地共享一些公共字段,但您确实不能像这样组合多个接口。也许在这里考虑组合(例如使用 Embeddables)而不是继承?
标签: hibernate jpa spring-data-jpa spring-data self-referencing-table