如何映射具有 OneToMany 关系的两个抽象 InheritanceType.TABLE_PER_CLASS 实体?
How do you map two abstract InheritanceType.TABLE_PER_CLASS entities with a OneToMany relationship?
我将 Hibernate 与 Spring Boot 和 JPA 一起使用,并且有一个业务需求来检索并合并到单个分页响应数据中,该数据存储在四个不同的 table 中数据库
我们将前两个 table 称为“tblCredits”,其中包含 Credits,以及“tblDebits”,其中包含 Debits。出于我们的目的,这两个 table 是相同的 - 相同的列名、相同的列类型、相同的 ID 字段,所有内容。我的端点应该能够 return 贷方和借方的组合列表,并且能够 search/sort 通过 any/all 被 return 编辑的字段,并且带分页。
如果我控制了那个数据库,我会简单地将两个 table 合并到一个 table 中,或者创建一个视图或存储过程来为我做这件事,但这是一个其他应用程序使用的遗留数据库,我无法以任何方式修改,所以这不是一个选项。
如果我不需要排序和分页,我可以只创建两个完全独立的实体,为每个实体创建一个单独的 Spring Data JPA 存储库,分别查询两个存储库,然后合并结果在我自己的代码中。但是特别是对组合结果进行分页会变得非常麻烦,我不想自己实现合并分页逻辑,除非我绝对必须这样做。理想情况下,我应该能够让 JPA 立即为我处理所有这些。
我已经能够为前两个 table 实现第一步,使用抽象 class 声明为 InheritanceType.TABLE_PER_CLASS 的实体,如下所示:
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class AbstractCreditDebitEntity {
/* literally all my properties and ID and column mappings here
...
*/
}
然后是扩展该抽象实体并简单指定两个不同 table 映射的两个具体 classes,根本没有 class 特定的属性或列映射:
@Entity
@Table(name = "tblCredits")
public final class Credit extends AbstractCreditDebitEntity {
//Literally nothing inside this class
}
@Entity
@Table(name = "tblDebits")
public final class Debit extends AbstractCreditDebitEntity {
//Literally nothing inside this class
}
到目前为止一切顺利,效果很好,我能够在 AbstractCreditDebitEntity 实体上创建一个 Spring JPA 存储库,在后台生成对两个 table 的联合查询,并且我能够通过适当的分页和排序在单个查询中从两个 table 中取回记录。 (联合查询的性能问题目前与我无关。)
然而,我在下一步中被绊倒了,当我合并另外两个 table 时。 tblCredits 与 tblCreditLineItems 具有一对多关系,而 tblDebits 与 tblDebitLineItems 具有一对多关系。同样,从我们的角度来看,tblCreditLineItems 和 tblDebitLineItems 是相同的 tables - 相同的列名、相同的列类型、相同的 ID 字段,所有内容。
所以我可以对那些子实体采用与以前相同的模式:
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class AbstractCreditDebitLineItemEntity {
/* literally all my properties and ID and column mappings here
...
*/
}
@Entity
@Table(name = "tblCreditLineItems")
public final class CreditLineItem extends AbstractCreditDebitLineItemEntity {
//Literally nothing inside this class
}
@Entity
@Table(name = "tblDebitLineItems")
public final class DebitLineItem extends AbstractCreditDebitLineItemEntity {
//Literally nothing inside this class
}
但现在我需要在 Credit/Debit 实体和 CreditLineItem/DebitLineItem 实体之间创建映射。这就是我挣扎的地方。因为我需要能够根据关联的 CreditLineItem/DebitLineItem 实体内的属性值来过滤我 return 哪些特定的 Credit/Debit 实体,所以我需要两个实体之间的双向映射,并且我一直无法成功运行。
这是我到目前为止的进展情况。首先是三个 Credit/Debit 实体,其 OneToMany 映射到它们关联的 CreditLineItem/DebitLineItem 实体:
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class AbstractCreditDebitEntity {
/* literally all my properties and ID and column mappings here
...
*/
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinColumn(
name = "MyIdColumnName",
referencedColumnName = "MyIdColumnName"
)
public abstract List<AbstractCreditDebitLineItemEntity> getCreditDebitLineItems();
public abstract void setCreditDebitLineItems(List<AbstractCreditDebitLineItemEntity> items);
}
@Entity
@Table(name = "tblCredits")
public final class Credit extends AbstractCreditDebitEntity {
private List<CreditLineItem> creditDebitLineItems;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, targetEntity = CreditLineItem.class)
@JoinColumn(
name = "MyIdColumnName",
referencedColumnName = "MyIdColumnName"
)
@Override
public List<AbstractCreditDebitLineItemEntity> getCreditDebitLineItems() {
return Optional.ofNullable(creditDebitLineItems).stream()
.flatMap(List::stream)
.filter(value -> AbstractCreditDebitLineItemEntity.class.isAssignableFrom(value.getClass()))
.map(AbstractCreditDebitLineItemEntity.class::cast)
.collect(Collectors.toList());
}
@Override
public void setCreditDebitLineItems(List<AbstractCreditDebitLineItemEntity> items) {
creditDebitLineItems = Optional.ofNullable(items).stream()
.flatMap(List::stream)
.filter(value -> CreditLineItem.class.isAssignableFrom(value.getClass()))
.map(CreditLineItem.class::cast)
.collect(Collectors.toList());
}
}
@Entity
@Table(name = "tblDebits")
public final class Debit extends AbstractCreditDebitEntity {
private List<DebitLineItem> creditDebitLineItems;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, targetEntity = DebitLineItem.class)
@JoinColumn(
name = "MyIdColumnName",
referencedColumnName = "MyIdColumnName"
)
@Override
public List<AbstractCreditDebitLineItemEntity> getCreditDebitLineItems() {
return Optional.ofNullable(creditDebitLineItems).stream()
.flatMap(List::stream)
.filter(value -> AbstractCreditDebitLineItemEntity.class.isAssignableFrom(value.getClass()))
.map(AbstractCreditDebitLineItemEntity.class::cast)
.collect(Collectors.toList());
}
@Override
public void setCreditDebitLineItems(List<AbstractCreditDebitLineItemEntity> items) {
creditDebitLineItems = Optional.ofNullable(items).stream()
.flatMap(List::stream)
.filter(value -> DebitLineItem.class.isAssignableFrom(value.getClass()))
.map(DebitLineItem.class::cast)
.collect(Collectors.toList());
}
}
然后三个 CreditLineItem/DebitLineItem 实体及其 ManyToOne 映射回到 Credit/Debit 实体:
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class AbstractCreditDebitLineItemEntity {
/* literally all my properties and ID and column mappings here
...
*/
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(
name = "MyIdColumnName",
referencedColumnName = "MyIdColumnName",
updatable = false,
insertable = false)
public abstract AbstractCreditDebitEntity getCreditDebit();
public abstract void setCreditDebit(AbstractCreditDebitEntity creditDebitEntity);
}
@Entity
@Table(name = "tblCreditLineItems")
public final class CreditLineItem extends AbstractCreditDebitLineItemEntity {
private Credit creditDebit;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(
name = "MyIdColumnName",
referencedColumnName = "MyIdColumnName",
updatable = false,
insertable = false)
@Override
public Credit getCreditDebit() {
return creditDebit;
}
@Override
public void setCreditDebit(AbstractCreditDebitEntity creditDebitEntity) {
creditDebit =
Optional.ofNullable(creditDebitEntity)
.filter(value -> Credit.class.isAssignableFrom(value.getClass()))
.map(Credit.class::cast)
.orElse(throw new RuntimeException());
}
}
@Entity
@Table(name = "tblDebitLineItems")
public final class DebitLineItem extends AbstractCreditDebitLineItemEntity {
private Debit creditDebit;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(
name = "MyIdColumnName",
referencedColumnName = "MyIdColumnName",
updatable = false,
insertable = false)
@Override
public Debit getCreditDebit() {
return creditDebit;
}
@Override
public void setCreditDebit(AbstractCreditDebitEntity creditDebitEntity) {
creditDebit =
Optional.ofNullable(creditDebitEntity)
.filter(value -> Debit.class.isAssignableFrom(value.getClass()))
.map(Debit.class::cast)
.orElse(throw new RuntimeException());
}
}
这段代码可以编译,但是...当我在我的自动化测试中尝试保留我的信用实体之一(我使用一个简单的 H2 数据库进行我的自动化测试)时,我收到以下错误:
2021-04-02 13:53:52 [main] DEBUG org.hibernate.SQL T: S: - update AbstractCreditDebitLineItemEntity set MyIdColumnName=? where ID=?
2021-04-02 13:53:52 [main] DEBUG o.h.e.jdbc.spi.SqlExceptionHelper T: S: - could not prepare statement [update AbstractCreditDebitLineItemEntity set MyIdColumnName=? where ID=?]
org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "ABSTRACTCREDITDEBITLINEITEMENTITY" does not exist
根据从我的 AbstractCreditDebitEntity class 到我的 AbstractCreditDebitLineItemEntity 的 @OneToMany 映射,它似乎试图坚持下去。其中,因为它是一个带有 InheritanceType.TABLE_PER_CLASS 的抽象 class,没有为它指定 table,所以它假定它需要坚持的 table 与 class.
我想在这里发生的是 Credit subclass 中具体 getter 上的 @OneToMany 映射,它将其 targetEntity 指定为具体 CreditLineItem.class,本质上override/replace @OneToMany 映射到其父抽象 class。但似乎具体 class 上的映射被完全忽略了?
我可以从 AbstractCreditDebitEntity class 中完全删除 @OneToMany 映射,并且只在扩展它的两个具体 Credit/Debit 实体中定义该映射。这使得持久性错误消失,并且我的测试用例的 90% 通过了......但是在那种情况下,当我尝试过滤或排序从组合的 AbstractCreditDebitEntity Spring Data JPA 存储库返回的结果时,基于以下之一仅存在于 CreditLineItem/DebitLineItem 子实体中的字段,由于 AbstractCreditDebitEntity 不再具有到 AbstractCreditDebitLineItemEntity 的任何映射,因此查询失败。
有没有解决这个问题的好方法,使得从AbstractCreditDebitEntity到AbstractCreditDebitLineItemEntity的OneToMany映射仍然存在,但是知道Credit实体具体映射到CreditLineItem实体,Debit实体具体映射到DebitLineItem实体也维护了?
经过大量试验,我找到了适合我的东西。
基本上,与其尝试用具体实体中的 OneToMany 映射覆盖抽象实体 class 中的 OneToMany 映射,我不得不让它们完全分离映射到完全不同的属性。这意味着我的具体实体有两个不同的 AbstractCreditDebitLineItemEntity 集合,一些 AbstractCreditDebitLineItemEntity 对象将在两个集合中出现两次。在 memory/computation 方面有点浪费,但我同意,它有效!
这就是我最终得到的结果:
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class AbstractCreditDebitEntity {
/* literally all my properties and ID and column mappings here
...
*/
private List<AbstractCreditDebitLineItemEntity> creditDebitLineItems;
@OneToMany(fetch = FetchType.LAZY, targetEntity = AbstractCreditDebitLineItemEntity.class)
@JoinColumn(
name = "MyIdColumnName",
referencedColumnName = "MyIdColumnName",
updatable = false,
insertable = false
)
public List<AbstractCreditDebitLineItemEntity> getCreditDebitLineItems() {
return creditDebitLineItems;
}
public void setCreditDebitLineItems(List<AbstractCreditDebitLineItemEntity> items) {
creditDebitLineItems = items;
}
}
@Entity
@Table(name = "tblCredits")
public final class Credit extends AbstractCreditDebitEntity {
private List<CreditLineItem> creditLineItems;
@OneToMany(cascade = CascadeType.ALL, targetEntity = CreditLineItem.class)
@LazyCollection(LazyCollectionOption.FALSE)
@JoinColumn(
name = "MyIdColumnName",
referencedColumnName = "MyIdColumnName"
)
public List<CreditLineItem> getCreditLineItems() {
return creditLineItems;
}
@Override
public void setCreditDebitLineItems(List<CreditLineItem> items) {
creditLineItems = items;
}
}
对借方实体重复完全相同的模式。
这让我可以:
坚持使用从具体的 Credit 和 Debit 实体到具体的 CreditLineItem 和 DebitLineItem 实体的 OneToMany 映射;和
do 使用从该抽象实体到 AbstractCreditDebitLineItemEntity 的完全独立的 OneToMany 映射在 AbstractCreditDebitEntity 的 Spring Data JPA 存储库中找到。
不像我能够用具体子 class 中更具体的 OneToMany 映射覆盖抽象父 class 中的 OneToMany 映射那样干净...但是我说,有用!
(关于这个问题的答案让我知道我需要用 @LazyCollection(LazyCollectionOption.FALSE) 替换具体的 OneToMany 映射中的 fetchType=FetchType.EAGER:
Hibernate throws MultipleBagFetchException - cannot simultaneously fetch multiple bags)
我将 Hibernate 与 Spring Boot 和 JPA 一起使用,并且有一个业务需求来检索并合并到单个分页响应数据中,该数据存储在四个不同的 table 中数据库
我们将前两个 table 称为“tblCredits”,其中包含 Credits,以及“tblDebits”,其中包含 Debits。出于我们的目的,这两个 table 是相同的 - 相同的列名、相同的列类型、相同的 ID 字段,所有内容。我的端点应该能够 return 贷方和借方的组合列表,并且能够 search/sort 通过 any/all 被 return 编辑的字段,并且带分页。
如果我控制了那个数据库,我会简单地将两个 table 合并到一个 table 中,或者创建一个视图或存储过程来为我做这件事,但这是一个其他应用程序使用的遗留数据库,我无法以任何方式修改,所以这不是一个选项。
如果我不需要排序和分页,我可以只创建两个完全独立的实体,为每个实体创建一个单独的 Spring Data JPA 存储库,分别查询两个存储库,然后合并结果在我自己的代码中。但是特别是对组合结果进行分页会变得非常麻烦,我不想自己实现合并分页逻辑,除非我绝对必须这样做。理想情况下,我应该能够让 JPA 立即为我处理所有这些。
我已经能够为前两个 table 实现第一步,使用抽象 class 声明为 InheritanceType.TABLE_PER_CLASS 的实体,如下所示:
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class AbstractCreditDebitEntity {
/* literally all my properties and ID and column mappings here
...
*/
}
然后是扩展该抽象实体并简单指定两个不同 table 映射的两个具体 classes,根本没有 class 特定的属性或列映射:
@Entity
@Table(name = "tblCredits")
public final class Credit extends AbstractCreditDebitEntity {
//Literally nothing inside this class
}
@Entity
@Table(name = "tblDebits")
public final class Debit extends AbstractCreditDebitEntity {
//Literally nothing inside this class
}
到目前为止一切顺利,效果很好,我能够在 AbstractCreditDebitEntity 实体上创建一个 Spring JPA 存储库,在后台生成对两个 table 的联合查询,并且我能够通过适当的分页和排序在单个查询中从两个 table 中取回记录。 (联合查询的性能问题目前与我无关。)
然而,我在下一步中被绊倒了,当我合并另外两个 table 时。 tblCredits 与 tblCreditLineItems 具有一对多关系,而 tblDebits 与 tblDebitLineItems 具有一对多关系。同样,从我们的角度来看,tblCreditLineItems 和 tblDebitLineItems 是相同的 tables - 相同的列名、相同的列类型、相同的 ID 字段,所有内容。
所以我可以对那些子实体采用与以前相同的模式:
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class AbstractCreditDebitLineItemEntity {
/* literally all my properties and ID and column mappings here
...
*/
}
@Entity
@Table(name = "tblCreditLineItems")
public final class CreditLineItem extends AbstractCreditDebitLineItemEntity {
//Literally nothing inside this class
}
@Entity
@Table(name = "tblDebitLineItems")
public final class DebitLineItem extends AbstractCreditDebitLineItemEntity {
//Literally nothing inside this class
}
但现在我需要在 Credit/Debit 实体和 CreditLineItem/DebitLineItem 实体之间创建映射。这就是我挣扎的地方。因为我需要能够根据关联的 CreditLineItem/DebitLineItem 实体内的属性值来过滤我 return 哪些特定的 Credit/Debit 实体,所以我需要两个实体之间的双向映射,并且我一直无法成功运行。
这是我到目前为止的进展情况。首先是三个 Credit/Debit 实体,其 OneToMany 映射到它们关联的 CreditLineItem/DebitLineItem 实体:
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class AbstractCreditDebitEntity {
/* literally all my properties and ID and column mappings here
...
*/
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinColumn(
name = "MyIdColumnName",
referencedColumnName = "MyIdColumnName"
)
public abstract List<AbstractCreditDebitLineItemEntity> getCreditDebitLineItems();
public abstract void setCreditDebitLineItems(List<AbstractCreditDebitLineItemEntity> items);
}
@Entity
@Table(name = "tblCredits")
public final class Credit extends AbstractCreditDebitEntity {
private List<CreditLineItem> creditDebitLineItems;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, targetEntity = CreditLineItem.class)
@JoinColumn(
name = "MyIdColumnName",
referencedColumnName = "MyIdColumnName"
)
@Override
public List<AbstractCreditDebitLineItemEntity> getCreditDebitLineItems() {
return Optional.ofNullable(creditDebitLineItems).stream()
.flatMap(List::stream)
.filter(value -> AbstractCreditDebitLineItemEntity.class.isAssignableFrom(value.getClass()))
.map(AbstractCreditDebitLineItemEntity.class::cast)
.collect(Collectors.toList());
}
@Override
public void setCreditDebitLineItems(List<AbstractCreditDebitLineItemEntity> items) {
creditDebitLineItems = Optional.ofNullable(items).stream()
.flatMap(List::stream)
.filter(value -> CreditLineItem.class.isAssignableFrom(value.getClass()))
.map(CreditLineItem.class::cast)
.collect(Collectors.toList());
}
}
@Entity
@Table(name = "tblDebits")
public final class Debit extends AbstractCreditDebitEntity {
private List<DebitLineItem> creditDebitLineItems;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, targetEntity = DebitLineItem.class)
@JoinColumn(
name = "MyIdColumnName",
referencedColumnName = "MyIdColumnName"
)
@Override
public List<AbstractCreditDebitLineItemEntity> getCreditDebitLineItems() {
return Optional.ofNullable(creditDebitLineItems).stream()
.flatMap(List::stream)
.filter(value -> AbstractCreditDebitLineItemEntity.class.isAssignableFrom(value.getClass()))
.map(AbstractCreditDebitLineItemEntity.class::cast)
.collect(Collectors.toList());
}
@Override
public void setCreditDebitLineItems(List<AbstractCreditDebitLineItemEntity> items) {
creditDebitLineItems = Optional.ofNullable(items).stream()
.flatMap(List::stream)
.filter(value -> DebitLineItem.class.isAssignableFrom(value.getClass()))
.map(DebitLineItem.class::cast)
.collect(Collectors.toList());
}
}
然后三个 CreditLineItem/DebitLineItem 实体及其 ManyToOne 映射回到 Credit/Debit 实体:
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class AbstractCreditDebitLineItemEntity {
/* literally all my properties and ID and column mappings here
...
*/
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(
name = "MyIdColumnName",
referencedColumnName = "MyIdColumnName",
updatable = false,
insertable = false)
public abstract AbstractCreditDebitEntity getCreditDebit();
public abstract void setCreditDebit(AbstractCreditDebitEntity creditDebitEntity);
}
@Entity
@Table(name = "tblCreditLineItems")
public final class CreditLineItem extends AbstractCreditDebitLineItemEntity {
private Credit creditDebit;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(
name = "MyIdColumnName",
referencedColumnName = "MyIdColumnName",
updatable = false,
insertable = false)
@Override
public Credit getCreditDebit() {
return creditDebit;
}
@Override
public void setCreditDebit(AbstractCreditDebitEntity creditDebitEntity) {
creditDebit =
Optional.ofNullable(creditDebitEntity)
.filter(value -> Credit.class.isAssignableFrom(value.getClass()))
.map(Credit.class::cast)
.orElse(throw new RuntimeException());
}
}
@Entity
@Table(name = "tblDebitLineItems")
public final class DebitLineItem extends AbstractCreditDebitLineItemEntity {
private Debit creditDebit;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(
name = "MyIdColumnName",
referencedColumnName = "MyIdColumnName",
updatable = false,
insertable = false)
@Override
public Debit getCreditDebit() {
return creditDebit;
}
@Override
public void setCreditDebit(AbstractCreditDebitEntity creditDebitEntity) {
creditDebit =
Optional.ofNullable(creditDebitEntity)
.filter(value -> Debit.class.isAssignableFrom(value.getClass()))
.map(Debit.class::cast)
.orElse(throw new RuntimeException());
}
}
这段代码可以编译,但是...当我在我的自动化测试中尝试保留我的信用实体之一(我使用一个简单的 H2 数据库进行我的自动化测试)时,我收到以下错误:
2021-04-02 13:53:52 [main] DEBUG org.hibernate.SQL T: S: - update AbstractCreditDebitLineItemEntity set MyIdColumnName=? where ID=?
2021-04-02 13:53:52 [main] DEBUG o.h.e.jdbc.spi.SqlExceptionHelper T: S: - could not prepare statement [update AbstractCreditDebitLineItemEntity set MyIdColumnName=? where ID=?]
org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "ABSTRACTCREDITDEBITLINEITEMENTITY" does not exist
根据从我的 AbstractCreditDebitEntity class 到我的 AbstractCreditDebitLineItemEntity 的 @OneToMany 映射,它似乎试图坚持下去。其中,因为它是一个带有 InheritanceType.TABLE_PER_CLASS 的抽象 class,没有为它指定 table,所以它假定它需要坚持的 table 与 class.
我想在这里发生的是 Credit subclass 中具体 getter 上的 @OneToMany 映射,它将其 targetEntity 指定为具体 CreditLineItem.class,本质上override/replace @OneToMany 映射到其父抽象 class。但似乎具体 class 上的映射被完全忽略了?
我可以从 AbstractCreditDebitEntity class 中完全删除 @OneToMany 映射,并且只在扩展它的两个具体 Credit/Debit 实体中定义该映射。这使得持久性错误消失,并且我的测试用例的 90% 通过了......但是在那种情况下,当我尝试过滤或排序从组合的 AbstractCreditDebitEntity Spring Data JPA 存储库返回的结果时,基于以下之一仅存在于 CreditLineItem/DebitLineItem 子实体中的字段,由于 AbstractCreditDebitEntity 不再具有到 AbstractCreditDebitLineItemEntity 的任何映射,因此查询失败。
有没有解决这个问题的好方法,使得从AbstractCreditDebitEntity到AbstractCreditDebitLineItemEntity的OneToMany映射仍然存在,但是知道Credit实体具体映射到CreditLineItem实体,Debit实体具体映射到DebitLineItem实体也维护了?
经过大量试验,我找到了适合我的东西。
基本上,与其尝试用具体实体中的 OneToMany 映射覆盖抽象实体 class 中的 OneToMany 映射,我不得不让它们完全分离映射到完全不同的属性。这意味着我的具体实体有两个不同的 AbstractCreditDebitLineItemEntity 集合,一些 AbstractCreditDebitLineItemEntity 对象将在两个集合中出现两次。在 memory/computation 方面有点浪费,但我同意,它有效!
这就是我最终得到的结果:
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class AbstractCreditDebitEntity {
/* literally all my properties and ID and column mappings here
...
*/
private List<AbstractCreditDebitLineItemEntity> creditDebitLineItems;
@OneToMany(fetch = FetchType.LAZY, targetEntity = AbstractCreditDebitLineItemEntity.class)
@JoinColumn(
name = "MyIdColumnName",
referencedColumnName = "MyIdColumnName",
updatable = false,
insertable = false
)
public List<AbstractCreditDebitLineItemEntity> getCreditDebitLineItems() {
return creditDebitLineItems;
}
public void setCreditDebitLineItems(List<AbstractCreditDebitLineItemEntity> items) {
creditDebitLineItems = items;
}
}
@Entity
@Table(name = "tblCredits")
public final class Credit extends AbstractCreditDebitEntity {
private List<CreditLineItem> creditLineItems;
@OneToMany(cascade = CascadeType.ALL, targetEntity = CreditLineItem.class)
@LazyCollection(LazyCollectionOption.FALSE)
@JoinColumn(
name = "MyIdColumnName",
referencedColumnName = "MyIdColumnName"
)
public List<CreditLineItem> getCreditLineItems() {
return creditLineItems;
}
@Override
public void setCreditDebitLineItems(List<CreditLineItem> items) {
creditLineItems = items;
}
}
对借方实体重复完全相同的模式。
这让我可以:
坚持使用从具体的 Credit 和 Debit 实体到具体的 CreditLineItem 和 DebitLineItem 实体的 OneToMany 映射;和
do 使用从该抽象实体到 AbstractCreditDebitLineItemEntity 的完全独立的 OneToMany 映射在 AbstractCreditDebitEntity 的 Spring Data JPA 存储库中找到。
不像我能够用具体子 class 中更具体的 OneToMany 映射覆盖抽象父 class 中的 OneToMany 映射那样干净...但是我说,有用!
(关于这个问题的答案让我知道我需要用 @LazyCollection(LazyCollectionOption.FALSE) 替换具体的 OneToMany 映射中的 fetchType=FetchType.EAGER: Hibernate throws MultipleBagFetchException - cannot simultaneously fetch multiple bags)