我有两个实体
class A {
...
Integer totalSum;
Set<B> b;
}
class B {
...
Integer value;
A container;
}
我希望a.totalSum是每个a.b.value的总和;
也许最好的解决方案是在db中查看,但我想在BRepository中监听更改并更新A记录。
我做:
@PostPersist
@PostUpdate
@PostRemove
private void recalculateSums(B b) {
AutowireHelper.autowire(this, this.aRepository);
AutowireHelper.autowire(this, this.bRepository);
A a = b.getContainer();
a.setTotalSum(bRepository.sumByA(s));
aRepository.save(s);
}
在BRepository:
@Query("select sum(b.value) from B b where b.container = :a")
Long sumByA(@Param("a") A a);
我有错误:org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint ["PRIMARY KEY ON PUBLIC.B(ID)"; SQL statement:
insert into b (VALUE, CONTAINER_ID, ID) values (?, ?, ?)
我做错了什么?
如果我这样做
a.setTotalSum(a.getTotalSum()+1);
aRepository.save(s);
一切正常,但如果我这样做
a.setTotalSum(a.getTotalSum()+1);
aRepository.saveAndFlush(s);
我有同样的错误。
答案 0 :(得分:2)
我可以看到为什么你可能想要这样做,但我认为这会产生大量关于数据完整性的潜在问题。
如果您希望A的总和不必加载并迭代所有B,那么您可以实现其他三个选项,所有这些选项都比您的提议更强大。
如您所述,创建一个视图。然后,您可以将实体说明,SummaryData映射到此视图,并将A从一对一映射到SummaryData,以便您可以执行a.getSummaryData()。getTotalSum();
或者,您可以使用Hibernate特定的@Formula注释,它将在加载实体时发出内联选择。
@Formula(&#34;(从B b内部连接A a中选择sum(value),其中b.a_id = a.id和a.id = id private int totalSum;
最后,根据数据库的功能,您可以像创建任何其他字段一样创建虚拟列并映射属性。
1和3显然需要架构更改,但您的应用仍将符合JPA标准。 2不需要任何架构更改,但如果这很重要,则会违反严格的JPA规范。